2. 工廠方法模式html
(1)概念java
工廠方法模式的定義是:定義一個用於建立對象的接口,讓子類決定實現哪個類。設計模式
即工廠父類負責定義建立產品對象的公共接口,工廠子類負責生成具體的產品對象。框架
將產品類的實例化操做延遲到工廠子類中完成,即經過工廠子類來肯定究竟應該實例化哪個具體產品類。dom
工廠方法模式是簡單工廠模式的延伸與改進,既繼承了其封裝性等優勢,又彌補了其缺陷(提升擴展性),使其符合原則的要求。ide
在工廠方法模式中,每個具體工廠只能生產一種具體產品。具體工廠與具體產品一一對應。工具
(2)類圖、典型代碼ui
Factory(抽象類或接口):抽象工廠類,聲明瞭工廠方法,用於返回一個產品。抽象工廠是工廠方法模式的核心,它與應用程序無關。spa
ConcreteFactory(實現類):具體工廠類,實現抽象工廠類中聲明的方法,可由客戶端調用,返回一個具體產品類的實例。設計
Product(抽象類或接口):抽象產品類,定義了產品的接口,是產品對象的共同父類或接口。
ConcreteProduct(實現類):具體產品類,實現了抽象產品類的方法,其具體產品由對應的具體工廠建立。
典型代碼以下:
//抽象工廠類 public interface Factory { public Product factoryMethod(); }
//具體工廠類之一 public class ConcreteFactory implements Factory { @Override public Product factoryMethod() { return new ConcreteFactory(); } }
(3)舉例
原有一個工廠生產一種電視機,現分爲兩個子工廠:海爾工廠生產海爾電視機,海信工廠生產海信電視機。
根據工廠方法模式設計類圖以下:
實現代碼以下:
//抽象產品類,定義全部產品必須實現的方法 public interface TV { public void play(); }
//具體產品類1--海爾電視 public class HaierTV implements TV { @Override public void play() { // 海爾電視的功能 System.out.println("海爾電視播放中..."); } }
//具體產品類2--海信電視 public class HisenseTV implements TV { @Override public void play() { // 海信電視的功能 System.out.println("海信電視播放中..."); } }
//抽象工廠類,定義全部工廠必須實現的方法 public interface TVFactory { public TV produceTV(); }
//具體產品類1--海爾電視 public class HaierTV implements TV { @Override public void play() { // 海爾電視的功能 System.out.println("海爾電視播放中..."); } }
//具體產品類2--海信電視 public class HisenseTV implements TV { @Override public void play() { // 海信電視的功能 System.out.println("海信電視播放中..."); } }
//客戶端調用類--調用具體電視工廠生產對應電視 public class Client { public static void main(String[] args) { TVFactory factory; TV tv; // 產生海爾電視並調用其功能 factory = new HaierTVFactory(); tv = factory.produceTV(); tv.play(); // 產生海信電視並調用其功能 factory = new HisenseTVFactory(); tv = factory.produceTV(); tv.play(); } }
輸出結果以下:
海爾電視播放中...
海信電視播放中...
若是此時還須要增長一種電視機品牌TCL,則只須要新建一個實現TV接口的具體產品類和一個實現TVFactory接口的具體工廠類便可,不須要修改其餘代碼:
//新增具體產品類3--TCL電視 public class TCLTV implements TV { @Override public void play() { // TCL電視的功能 System.out.println("TCL電視播放中..."); } }
//新增具體工廠類3--專門生產TCL電視的TCL工廠 public class TCLTVFactory implements TVFactory { @Override public TV produceTV() { // 生產一個TCL電視的對象 return new TCLTV(); } }
在客戶端調用類中增長調用TCL工廠生產TCL電視的語句:
// 產生TCL電視並調用其功能 factory = new TCLTVFactory(); tv = factory.produceTV(); tv.play();
輸出結果以下:
海爾電視播放中...
海信電視播放中...
TCL電視播放中...
(4)優缺點、適用場景
工廠方法模式的優勢:
用戶只需關心所需產品對應的工廠,無須關心建立細節(屏蔽產品類),甚至不須要知道具體產品的類名;
典型的解耦框架,高層模塊須要知道產品的抽象類,其餘的實現類都不用關心;
良好的封裝性,代碼結構清晰,優秀的擴展性,同時符合開閉原則。
工廠方法模式的缺點:
在添加新產品時成對增長了類的個數,增長了系統的複雜度,編譯和運行更多的類也會增長系統的開銷;
考慮到可擴展性引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度。
工廠方法模式的適用場景:
須要靈活、可擴展的框架時;
當一個類(好比客戶端類)不知道所須要的對象的類時(須要知道其對應的工廠);
一個類經過其子類來肯定建立那個對象。
3. 抽象工廠模式
(1)概念
抽象工廠模式的定義是:爲建立一組相關或相互依賴的對象提供一個接口,並且無需指定他們的具體類。
抽象工廠模式是工廠方法模式的泛化版,即工廠方法模式只是抽象工廠模式的一種特殊狀況。
在抽象工廠模式中,每個具體工廠能夠生產多個具體產品。
(2)類圖、典型代碼
AbstractFactory(抽象類或接口):抽象工廠類,用於聲明生產產品的方法。
ConcreteFactory(實現類):具體工廠類,具體實現生產產品的方法,返回一個具體產品。
AbstractProduct(抽象類或接口):抽象產品類,定義了每種產品的功能方法。
ConcreteProduct(實現類):具體產品類,具體實現了抽象產品類定義的功能方法。
典型代碼以下:
// 抽象工廠類 public interface AbstractFactory { public AbstractProductA createProductA(); public AbstractProductB createProductB(); }
// 具體工廠類之一 public class ConcreteFactory implements AbstractFactory{ public AbstractProductA createProductA(){ return new ConcreteProductA(); } public AbstractProductB createProductB(){ return new ConcreteProductB(); } }
(3)舉例
一個電器工廠能夠生產多種電器,好比海爾工廠能夠生產海爾電視和海爾空調,TCL工廠能夠生產TCL電視和TCL空調。
根據抽象工廠模式設計類圖以下:
實現代碼以下:
//抽象產品類1--電視類 public interface TV { public void play(); }
//電視具體產品類1--海爾電視 public class HaierTV implements TV { @Override public void play() { System.out.println("海爾電視播放中..."); } }
//電視具體產品類2--TCL電視 public class TCLTV implements TV { @Override public void play() { System.out.println("TCL電視播放中..."); } }
//抽象產品類2--空調類 public interface AirConditioner { public void changeTemperature(); }
//空調具體產品類1--海爾空調 public class HaierAirConditioner implements AirConditioner { @Override public void changeTemperature() { System.out.println("海爾空調吹風中..."); } }
//空調具體產品類2--TCL空調 public class TCLAirConditioner implements AirConditioner { @Override public void changeTemperature() { System.out.println("TCL空調吹風中..."); } }
//抽象工廠類,定義全部工廠必須實現的方法 public interface Factory { public TV produceTV(); public AirConditioner produceAirConditioner(); }
//具體工廠類1--海爾工廠 public class HaierFactory implements Factory{ @Override public TV produceTV() { return new HaierTV(); } @Override public AirConditioner produceAirConditioner() { return new HaierAirConditioner(); } }
//具體工廠類2--TCL工廠 public class TCLFactory implements Factory{ @Override public TV produceTV() { return new TCLTV(); } @Override public AirConditioner produceAirConditioner() { return new TCLAirConditioner(); } }
運行結果以下:
海爾電視播放中...
海爾空調吹風中...
———————————————
TCL電視播放中...
TCL空調吹風中...
(4)優缺點、適用場景
抽象工廠模式的優勢:
隔離了具體類的生成,使客戶並不知道什麼被建立;
產品內的約束爲非公開狀態(好比不一樣產品的生產比例,這對調用工廠類的高層模塊是透明的);
抽象工廠模式的缺點:
在添加新的產品對象時,難以擴展抽象工廠來生產新種類的產品(對接口進行擴展會致使全部子類的修改);
抽象工廠模式的適用場景:
一個系統不依賴產品類實例如何被建立、組合和表達的細節時;
系統中有多個產品族,而每次只使用其中某一產品族時;
屬於同一產品族的產品將一塊兒使用;
多個對象有相同的約束時。
在實際的應用開發中,通常將具體類的類名寫入配置文件中,再經過Java的反射機制讀取XML格式的配置文件,根據存儲在XML文件中的類名字符串生成對象。
新建XML文件config.xml以下:
<?xml version="1.0" encoding="UTF-8"?> <config> <className>xxxFactory</className> </config>
新建工具類文件XMLUtil.java以下:
package com.test.util; import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XMLUtil { // 該方法用於從XML配置文件中提取類名字符串,並返回一個實例對象 public static Object getBean() { try { // 建立DOM文檔對象 DocumentBuilderFactory dFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = dFactory.newDocumentBuilder(); Document doc = builder.parse(new File( "./src/com/test/util/config.xml"));// 若不在同一路徑下,必須指定文件具體路徑,用正斜槓/或雙反斜槓\\ // 獲取包含類名的文本節點 NodeList nlist = doc.getElementsByTagName("className"); Node classNode = nlist.item(0).getFirstChild(); String cName = classNode.getNodeValue(); // 經過類名生成實例對象並將其返回 Class c = Class.forName("com.test.factory_method." + cName);// 若不在同一路徑下,必須寫出類的全名 Object obj = c.newInstance(); return obj; } catch (Exception e) { e.printStackTrace(); } return null; } }
改進工廠方法模式中的客戶端代碼以下:
//客戶端調用類--調用具體電視工廠生產對應電視 public class Client { public static void main(String[] args) { TVFactory factory; TV tv; // // 產生海爾電視並調用其功能 // factory = new HaierTVFactory(); // tv = factory.produceTV(); // tv.play(); // // // 產生海信電視並調用其功能 // factory = new HisenseTVFactory(); // tv = factory.produceTV(); // tv.play(); // // // 產生TCL電視並調用其功能 // factory = new TCLTVFactory(); // tv = factory.produceTV(); // tv.play(); // 將具體類名寫入配置文件中,再經過Java反射機制讀取XML格式文件,根據類名生成對象並返回 factory = (TVFactory) XMLUtil.getBean(); tv = factory.produceTV(); tv.play(); } }
將config.xml文件中的「xxxFactory」更改成須要生成對象的類名「HaierTVFactory」,運行客戶端結果以下:
海爾電視播放中...
抽象工廠模式中例子的客戶端改進與此相同。
6大設計原則,與常見設計模式(概述):http://www.cnblogs.com/LangZXG/p/6204142.html
類圖基礎知識:http://www.cnblogs.com/LangZXG/p/6208716.html