工廠模式java
簡單工廠模式:數據庫
1.建立Car接口安全
public interface Car { public void drive(); }
2.建立兩個實體類,分別實現Car接口多線程
public class Benz implements Car { @Override public void drive() { System.out.println("Driving Benz"); } }
public class Bmw implements Car { @Override public void drive() { System.out.println("Driving Bmw"); } }
3.建立Driver工廠,根據傳過來的值建立不一樣的對象併發
public class DriverFactory { public Car drivercar(String key){ if("Benz".equals(key)){ return new Benz(); }else if("Bwm".equals(key)){ return new Bmw(); } return null; } }
4.測試ide
public class TestFactory { @Test public void test() { DriverFactory dirver = new DriverFactory(); Car car1= dirver.drivercar("Bwm"); car1.drive(); Car car2 = dirver.drivercar("Benz"); car2.drive(); } }
工廠方法模式:函數
包括:工具
1.抽象產品:產品對象同一的基類,或者是同一的接口。性能
2.具體的產品:各個不一樣的實例對象類測試
3.抽象工廠:全部的子類工廠類的基類,或是同一的接口
4.具體的工廠子類:負責每一個不一樣的產品對象的實際建立
工廠方法的優缺點
工廠方法模式的優勢:
(1)在工廠方法模式中,工廠方法用來建立客戶所須要的產品,同時還向客戶隱藏了哪一種具體產品類將被實例化這一細節,用戶只須要關心所需產品對應的工廠,無需關心建立細節,甚至無需知道具體產品類的類名。
(2)基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它可以使工廠能夠自主肯定建立何種產品對象,而如何建立這個對象的細節則徹底封裝在具體工廠內部。工廠方法模式之因此又被稱爲多態工廠模式,正是由於全部的具體工廠類都具備同一抽象父類。
(3)使用工廠方法模式的另外一個優勢是在系統中加入新產品時,無需修改抽象工廠和抽象產品提供的接口,無需修改客戶端,也無需修改其餘的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就能夠了,這樣,系統的可擴展性也就變得很是好,徹底符合「開閉原則」。
工廠方法模式的缺點以下:
(1)在添加新產品時,須要編寫新的具體產品類,並且還要提供與之對應的具體工廠類,系統中類的個數將成對增長,在必定程度上增長了系統的複雜度,有更多的類須要編譯和運行,會給系統帶來一些額外的開銷。
(2)因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度,且在實現時可能須要用到DOM、反射等技術,增長了系統的實現難度。
工廠方法模式的適用環境
在如下狀況下可使用工廠方法模式:
(1)一個類不知道它所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;客戶端須要知道建立具體產品的工廠類。
(2)一個類經過其子類來指定建立哪一個對象:在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
(3)將建立對象的任務委託給多個工廠子類中的某一個,客戶端在使用時能夠無需關心是哪個工廠子類建立產品子類,須要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
步驟:
1.抽象的產品類
public interface TV { public void play(); }
2.具體的產品類
public class HaierTV implements TV { @Override public void play() { System.out.println("海爾電視播放中....."); } }
public class XimiTV implements TV { @Override public void play() { System.out.println("小米電視播放中....."); } }
3.抽象的工廠類
public interface TVFactory { public TV productTV(); }
4.具體的工廠類
public class HaierTVFactory implements TVFactory { @Override public TV productTV() { System.out.println("海爾電視工廠生產海爾電視....."); return new HaierTV(); } }
public class XimiTVFactory implements TVFactory { @Override public TV productTV() { System.out.println("小米電視工廠生產海爾電視....."); return new XimiTV(); } }
5.測試
public class TestFactory { @Test public void test(){ TVFactory tvf1 = new HaierTVFactory(); TV tv1 = tvf1.productTV(); tv1.play(); TVFactory tvf2 = new XimiTVFactory(); TV tv2 = tvf2.productTV(); tv2.play(); } }
抽象工廠模式:
當每一個抽象產品都有多於一個的具體子類的時候(乘車工具備兩種、早餐有兩種),工廠角色怎麼知道實例化哪個子類呢?好比每一個抽象產品角色都有兩個具體產品(人有窮人和富人)。抽象工廠模式提供兩個具體工廠角色(窮人工廠和富人工廠),分別對應於這兩個具體產品角色(窮人騎自行車和橙汁;富人坐公交喝牛奶),每個具體工廠角色只負責某一個產品角色的實例化。每個具體工廠類只負責建立抽象產品的某一個具體子類的實例。
1.抽象產品接口:定義產品的接口,公共的暴露方法。便於實際的產品類實現。
2.具體的產品類:包含實際產品的類的邏輯處理:
3.抽象工廠接口:定義產生系列對象的接口
4.具體的工廠實現:實現抽象的接口工廠,返回具體的產品類的實現。
步驟:
1.抽象的產品接口
public interface Car { public void gotowork(); }
public interface BreakFast { public void eat(); }
2.具體的產品類
1)Car
public class Bike implements Car { @Override public void gotowork() { System.out.println("騎自行車去工做...."); } }
public class Bus implements Car { @Override public void gotowork() { System.out.println("坐公交去工做...."); } }
2)BreakFast類
public class Milk implements BreakFast { @Override public void eat() { System.out.println("早餐喝牛奶....."); } }
public class Orange implements BreakFast { @Override public void eat() { System.out.println("早餐喝橙汁....."); } }
3.抽象的工廠類
public interface AbstractFactory { public Car getcar(); public BreakFast getbreakfast(); }
4.具體的工廠類
public class LowPersonFactory implements AbstractFactory { @Override public Car getcar() { return new Bike(); } @Override public BreakFast getbreakfast() { return new Orange(); } }
public class HighPersonFactory implements AbstractFactory { @Override public Car getcar() { return new Bus(); } @Override public BreakFast getbreakfast() { return new Milk(); } }
5.測試
public class TestFactory { @Test public void test3(){ AbstractFactory lowfactory = new LowPersonFactory(); Car car = lowfactory.getcar(); BreakFast breakFast = lowfactory.getbreakfast(); System.out.println("早飯:"); breakFast.eat(); System.out.println("上班交通工具是:"); car.gotowork(); AbstractFactory highfactory = new HighPersonFactory(); Car car2 = highfactory.getcar(); BreakFast getbreakfast2 = highfactory.getbreakfast(); System.out.println("早飯:"); getbreakfast2.eat(); System.out.println("上班交通工具是:"); car2.gotowork(); } }
單例模式:
主要介紹:懶漢式單例、餓漢式單例
特色:
1.單例類只能有一個實例
2.單例類必須本身建立本身的惟一實例
3.單例類必須給全部其餘的對象提供這一實例
一、餓漢式單例
public class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton newInstance(){ return instance; } }
從代碼中咱們看到,類的構造函數定義爲private的,保證其餘類不能實例化此類,而後提供了一個靜態實例並返回給調用者。
餓漢模式是最簡單的一種實現方式,餓漢模式在類加載的時候就對實例進行建立,實例在整個程序週期都存在。
它的好處是隻在類加載的時候建立一次實例,不會存在多個線程建立多個實例的狀況,避免了多線程同步的問題。它的缺點也很明顯,即便這個單例沒有用到也會被建立,並且在類加載以後就被建立,內存就被浪費了。
這種實現方式適合單例佔用內存比較小,在初始化時就會被用到的狀況。可是,若是單例佔用的內存比較大,或單例只是在某個特定場景下才會用到,使用餓漢模式就不合適了,這時候就須要用到懶漢模式進行延遲加載。
二、懶漢式單例
public class Singleton{ private static Singleton instance = null; private Singleton(){} public static Singleton newInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } }
懶漢模式中單例是在須要的時候纔去建立的,若是單例已經建立,再次調用獲取接口將不會從新建立新的對象,而是直接返回以前建立的對象。
若是某個單例使用的次數少,而且建立單例消耗的資源較多,那麼就須要實現單例的按需建立,這個時候使用懶漢模式就是一個不錯的選擇。
可是這裏的懶漢模式並無考慮線程安全問題,在多個線程可能會併發調用它的getInstance()方法,致使建立多個實例,所以須要加鎖解決線程同步問題,實現以下。
public class Singleton{ private static Singleton instance = null; private Singleton(){} public static synchronized Singleton newInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } }
三、雙重校驗鎖
加鎖的懶漢模式看起來即解決了線程併發問題,又實現了延遲加載,然而它存在着性能問題,依然不夠完美。synchronized修飾的同步方法比通常方法要慢不少,若是屢次調用getInstance(),累積的性能損耗就比較大了。所以就有了雙重校驗鎖,先看下它的實現代碼
public class Singleton { private static Singleton instance = null; private Singleton(){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
能夠看到上面在同步代碼塊外多了一層instance爲空的判斷。因爲單例對象只須要建立一次,若是後面再次調用getInstance()只須要直接返回單例對象。所以,大部分狀況下,調用getInstance()都不會執行到同步代碼塊,從而提升了程序性能。不過還須要考慮一種狀況,假如兩個線程A、B,A執行了if (instance == null)語句,它會認爲單例對象沒有建立,此時線程切到B也執行了一樣的語句,B也認爲單例對象沒有建立,而後兩個線程依次執行同步代碼塊,並分別建立了一個單例對象。爲了解決這個問題,還須要在同步代碼塊中增長if (instance == null)語句,也就是上面看到的代碼