Java ------ 工廠模式、單例模式

工廠模式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)語句,也就是上面看到的代碼

相關文章
相關標籤/搜索