工廠的三種模式:目的都是解耦
簡單工廠
工廠是一個類:生產各種各樣產品;不同類實現接口;業務全部在fractory中,違反了開閉原則。
使用在業務簡單的情況下。
工廠方法(如果工廠的產品全部屬於同一個等級結構,則屬於工廠方法。)
定義一個創建對象的工廠接口,讓子類決定實例化哪一個類,將實際工作交給子類
例子:
工廠是一個接口,produceTrunk() ,實現創建不同卡車類
卡車也是一個接口,實現不同卡車類
將不同卡車的業務邏輯抽離出fractory
優點
符合開閉原則,每增加一種產品,只需要增加相應具體的產品類和工廠子類。
符合單一職責原則,每個具體工廠類只負責創建對應的產品。
缺點
在增加一個新產品時,需要增加一個產品類和一個具體的子工廠,每個工廠生產一種產品,太過單一。
抽象工廠(如果工廠的產品來自多個等級結構,則屬於抽象工廠模式)
抽象工廠角色:具體工廠必須時間的接口。
具體工廠角色:和具體業務邏輯相關的代碼,創建對應的具體產品的對象。
抽象工廠:producetrunk(); producesedan();
具體工廠:寶馬工廠(寶馬轎車、寶馬卡車)奧迪工廠(奧迪轎車、奧迪卡車)
抽象產品:卡車、轎車
具體產品:寶馬卡車,寶馬轎車,奧迪卡車,奧迪轎車
單例模式
概念:包含一個被稱為單例的特殊類。
特點:單例類只能有一個實例;單例類必須自己創建自己的唯一實例;單例類必須給所有其他對象提供這一實例。
實現:private 構造類避免了外部類對此類進行實例化
場景需求:
1.計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。
2.創建的一個對象需要消耗的資源過多,比如IO與數據庫的連接等。
如何選擇:
餓漢式是線程安全的,但是類加載就創建對象。如果在一個工廠模式下,緩存了很多實例,就得考慮效率問題,因為這個類一加載就把所有實例一起創建了(不管用不用);懶漢式優點是延時加載,缺點是需要用同步。看實際需求選擇。
優點:在內存中只有一個實例,減少了內存開銷,尤其是頻繁創建和銷毀實例(工具類);避免對資源的多重占用(比如寫文件操作)
缺點:擴展很困難(private修飾的方法無法繼承,不能再擴展)
餓漢式單例
在類加載初始化時就創建好一個靜態的對象供外部使用,除非系統重啟,這個對象不會改變,本身是線程安全的。
package single; public class singlethon { //構造方法私有化 singlethon() {} private static singlethon single=new singlethon(); //對外提供調用 public static singlethon getinstance() { return single; } }
懶漢式單例
類加載的時候不創建對象,只有在使用的時候才創建,但是在多線程條件下,是線程不安全的。
package single; import javax.sql.rowset.spi.SyncFactory; public class single2 { private single2() {} private static single2 single=null; //同步鎖,一個線程執行時,其他線程處於等待 synchronized public static single2 getinstance() { if(single==null) { //線程不安全 try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } single=new single2(); } return single; } } //多線程,CPU 交替執行有先后
可以用同步鎖解決線程不安全問題,但是加鎖會降低效率;為提高效率,減小代碼同步范圍。但是用了雙重檢索,也不一定是線程安全的,因為還有系統指令重拍,此時可以將對象用volatile修飾。
package single; import javax.sql.rowset.spi.SyncFactory; public class single2 { private single2() {} private static single2 single=null; //同步鎖,一個線程執行時,其他線程處於等待 public static single2 getinstance() { //雙重檢索 if(single==null) { //線程不安全 synchronized(single2.class) { if(single==null) { single=new single2(); } } } return single; } } //多線程,CPU 交替執行有先后
靜態內部類
package single; public class single3 { private single3() {} //外部類被加載,內部類沒有被加載,除非主動使用 private static class insideclass { private static single3 single=new single3(); } public static single3 getinstance() { return insideclass.single; } }