設計模式之工廠方法模式

工廠,顧名思義在於對相關產品的批量添加,在開發中指將對象創建交給某個類,使得開發者不需要在意對象的創建。舉個例子,小青我的麪包店即將開業了。

/**
 * 
 * @author 小青
 * @Time 下午12:30:34
 * @Function:小青的麪包店
 *
 */
public class First {
	public static void main(String[] args) {
		System.out.println("小青的麪包店開業了");
		System.out.println("小青製作了一組黑麪包");
		System.out.println("小青製作了一組蜂蜜燕麥麪包");
		System.out.println("小青製作了一組白麪包");
	}
}
運行結果:


小青我發現,如果我還要製作其他類型的麪包呢?客戶端的代碼就會越來越龐大,而且改起來很是麻煩,經過一定的思考,我設計瞭如下操作

/**
 * 
 * @author ricardo
 * @Time 下午12:36:33
 * @Function:麪包師小青
 *
 */
public class BreadMaker {
	public static void GetBread(int breadType) {
		switch (breadType) {
		case 1:
			System.out.println("小青製作了一組黑麪包");			
			break;
		case 2:			
			System.out.println("小青製作了一組蜂蜜燕麥麪包");			
			break;
		case 3:		
			System.out.println("小青製作了一組白麪包");
			break;
		default:
			System.out.println("小青製作了一組新的麪包");
			break;
		}
	}
}
/**
 * 
 * @author ricardo
 * @Time 下午12:37:02
 * @Function:小青的麪包店
 *
 */
public class Second {
	public static void main(String[] args) {
		System.out.println("小青的麪包店開業了");
		System.out.println("顧客想要黑麪包");
		BreadMaker.GetBread(1);
		System.out.println("顧客想要蜂蜜燕麥麪包");
		BreadMaker.GetBread(2);
		System.out.println("顧客想要白麪包");
		BreadMaker.GetBread(3);
	}
}
運行截圖:


這樣的過程看上去就合理多了,但是要修改麪包師類也是很麻煩的,所以我決定再次修改拆分

/**
 * 
 * @author ricardo
 * @Time 下午12:42:29
 * @Function:麪包師
 *
 */
public class BreadMaker {
	public void GetBread() {
		System.out.println("製作麪包");
	}
}
/**
 * 
 * @author ricardo
 * @Time 下午12:45:19
 * @Function:製作黑麪包
 *
 */
public class BlackBread extends BreadMaker {

	@Override
	public void GetBread() {
		System.out.println("製作一組黑麪包");
	}
}
public class HoneyBread extends BreadMaker {
	@Override
	public void GetBread() {
		System.out.println("製作一組蜂蜜燕麥麪包");
	}
}
public class WhiteBread extends BreadMaker {
	@Override
	public void GetBread() {
		System.out.println("製作一組白麪包");
	}
}
將各種麪包都包裝成了BreadMaker的子類,重寫GetBread()方法,這樣在修改任何一種麪包的代碼都與其他麪包無關,同時還保證了麪包配方的安全性。

/**
 * 
 * @author ricardo
 * @Time 下午12:59:42
 * @Function:簡單面包工廠類
 *
 */
public class BreadFactory {
	public static BreadMaker MakeBread(int breadType) {
		BreadMaker breadMaker = null;
		switch (breadType) {
		case 1:
			breadMaker = new BlackBread();
			break;
		case 2:
			breadMaker = new HoneyBread();
			break;
		case 3:
			breadMaker = new WhiteBread();
			break;
		default:
			break;
		}
		return breadMaker;
	}
}

public class Second {
	public static void main(String[] args) {
		BreadMaker breadMaker;
		System.out.println("小青的麪包店開業了");
		System.out.println("顧客要黑麪包");
		breadMaker = BreadFactory.MakeBread(1);
		breadMaker.GetBread();
		System.out.println("顧客要白麪包");
		breadMaker.GetBread();
		breadMaker = BreadFactory.MakeBread(2);
		System.out.println("顧客要蜂蜜燕麥麪包");
		breadMaker = BreadFactory.MakeBread(3);
		breadMaker.GetBread();
	}
}

運行截圖:


以上採用的是簡單工廠模式,但是這樣做,在添加一種新麪包的時候,要修改工廠類,增加Case分支,對擴展開發的同時也對修改開放了,這讓小青我這個強迫症怎麼忍,於是,根據GOF對工廠方法的定義:定義一個創建對象的接口,讓子類決定實例化那一個類,工廠方法使一個類的實例化延遲到子類。再次對代碼進行修改

/**
 * 
 * @author ricardo
 * @Time 下午1:44:34
 * @Function:工廠接口
 *
 */
public interface IFactory {
	BreadMaker CreateBread();
}
public class BlackBreadFactory implements IFactory {

	@Override
	public BreadMaker CreateBread() {
		// TODO Auto-generated method stub
		return new BlackBread();
	}
}
public class HoneyBreadFactory implements IFactory {

	@Override
	public BreadMaker CreateBread() {
		// TODO Auto-generated method stub
		return new HoneyBread();
	}

}
public class WhiteBreadFactory implements IFactory {

	@Override
	public BreadMaker CreateBread() {
		// TODO Auto-generated method stub
		return new WhiteBread();
	}

}

客戶端實現對子類的實例化

public class Three {
	public static void main(String[] args) {
		BreadMaker breadMaker;
		System.out.println("小青的麪包店開業了!");
		
		System.out.println("顧客要買黑麪包");
		IFactory breadFactory = new BlackBreadFactory();
		breadMaker = breadFactory.CreateBread();
		breadMaker.GetBread();
		
		System.out.println("顧客要蜂蜜燕麥黑麪包");
		breadFactory = new HoneyBreadFactory();
		breadMaker = breadFactory.CreateBread();
		breadMaker.GetBread();
		
		System.out.println("顧客要買白麪包");
		breadFactory = new WhiteBreadFactory();
		breadMaker = breadFactory.CreateBread();
		breadMaker.GetBread();
	}
}

運行截圖:



這樣一來,新的代碼中增加新的麪包種類,只需要增加新麪包類和新的工廠方法接口實現就好了,具體的實例化哪個類的判斷放到了客戶端。

簡單工廠模式的最大優點是去除了客戶端與具體產品的依賴,雖然違背了開放-封閉原則,但是保持了封裝對象創建過程的優點。工廠方法模式在保留了簡單工廠模式優點的同時,也克服了其缺點,但對應的,每增加一個產品,都要添加一個產品工廠類,額外的增加了開發量。

以上內容,整理自劉徑舟,張玉華編著的《設計模式其實很簡單》讀書筆記,歡迎轉載.

發佈了38 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章