設計模式學習筆記(4) --抽象工廠
1.定義:
產品等級結構:產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。由不同工廠生產的同一型別的產品。
產品族:在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不同產品等級結構中的一組產品,如海爾電器工廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中。由一個工廠生產的一系列不同的產品。
抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬於物件建立型模式。
2.UML圖:
3.程式碼:
package com.skiff.www.factory.abstractFactory.product;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:27
* @Description:
*/
public interface AbstractApple {
abstract void pick();
}
package com.skiff.www.factory.abstractFactory.product; /** * @Auther: 一葉扁舟 * @Date: 2018/10/31 21:29 * @Description: */ public class NorthApple implements AbstractApple { @Override public void pick() { System.out.println("採摘北方的蘋果……"); } }
package com.skiff.www.factory.abstractFactory.product;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:30
* @Description:
*/
public class SourthApple implements AbstractApple {
@Override
public void pick() {
System.out.println("採摘南方的蘋果……");
}
}
package com.skiff.www.factory.abstractFactory.product; /** * @Auther: 一葉扁舟 * @Date: 2018/10/31 21:31 * @Description: */ public interface AbstractOrange { public abstract void pick(); }
package com.skiff.www.factory.abstractFactory.product;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:33
* @Description:
*/
public class NorthOrange implements AbstractOrange {
@Override
public void pick() {
System.out.println("採摘北方的橘子……");
}
}
package com.skiff.www.factory.abstractFactory.product;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:34
* @Description:
*/
public class SourthOrange implements AbstractOrange {
@Override
public void pick() {
System.out.println("採摘南方的橘子……");
}
}
package com.skiff.www.factory.abstractFactory.factory;
import com.skiff.www.factory.abstractFactory.product.AbstractApple;
import com.skiff.www.factory.abstractFactory.product.AbstractOrange;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:35
* @Description:
*/
public interface AbstractFactory {
AbstractOrange getOrange();
AbstractApple getApple();
}
package com.skiff.www.factory.abstractFactory.factory;
import com.skiff.www.factory.abstractFactory.product.AbstractApple;
import com.skiff.www.factory.abstractFactory.product.AbstractOrange;
import com.skiff.www.factory.abstractFactory.product.NorthApple;
import com.skiff.www.factory.abstractFactory.product.NorthOrange;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:36
* @Description:
*/
public class NorthFactory implements AbstractFactory {
@Override
public AbstractOrange getOrange() {
return new NorthOrange();
}
@Override
public AbstractApple getApple() {
return new NorthApple();
}
}
package com.skiff.www.factory.abstractFactory.factory;
import com.skiff.www.factory.abstractFactory.product.AbstractApple;
import com.skiff.www.factory.abstractFactory.product.AbstractOrange;
import com.skiff.www.factory.abstractFactory.product.SourthApple;
import com.skiff.www.factory.abstractFactory.product.SourthOrange;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:36
* @Description:
*/
public class SourthFactory implements AbstractFactory {
@Override
public AbstractOrange getOrange() {
return new SourthOrange();
}
@Override
public AbstractApple getApple() {
return new SourthApple();
}
}
package com.skiff.www.factory.abstractFactory;
import com.skiff.www.factory.abstractFactory.factory.AbstractFactory;
import com.skiff.www.factory.abstractFactory.factory.NorthFactory;
import com.skiff.www.factory.abstractFactory.factory.SourthFactory;
import com.skiff.www.factory.abstractFactory.product.AbstractApple;
import com.skiff.www.factory.abstractFactory.product.AbstractOrange;
import org.junit.Test;
/**
* @Auther: 一葉扁舟
* @Date: 2018/10/31 21:38
* @Description:
* 說明:北方的蘋果和南方的蘋果是一個產品等級結構,他們都是蘋果
* 北方的工廠生產蘋果和橘子,橘子和蘋果屬於一個產品族,是有同一家工廠生產的不同產品
*/
public class Client {
@Test
public void testAbstractFactory(){
System.out.println("北方工廠生產的水果:");
AbstractFactory factory = new NorthFactory();
AbstractApple apple = factory.getApple();
AbstractOrange orange = factory.getOrange();
apple.pick();
orange.pick();
System.out.println("----------------------------------");
System.out.println("南方工廠生產的水果:");
AbstractFactory sourthFactory = new SourthFactory();
AbstractOrange sourthOrange = sourthFactory.getOrange();
AbstractApple sourthApple = sourthFactory.getApple();
sourthApple.pick();
sourthOrange.pick();
}
}
4.優缺點:
(1)、抽象工廠模式的優點
抽象工廠模式隔離了具體類的生成,使得客戶並不需要知道什麼被建立。由於這種隔離,更換一個具體工廠就變得相對容易。所有的具體工廠都實現了抽象工廠中定義的那些公共介面,因此只需改變具體工廠的例項,就可以在某種程度上改變整個軟體系統的行為。
另外,應用抽象工廠模式可以實現高內聚低耦合的設計目的,因此抽象工廠模式得到了廣泛的應用。 當一個產品族中的多個物件被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的物件。這對一些需要根據當前環境來決定其行為的軟體系統來說,是一種非常實用的設計模式。 增加新的具體工廠和產品族很方便,無須修改已有系統,符合“開閉原則”。
(2)、抽象工廠模式的缺點
在新增新的產品物件時,品難以擴充套件抽象工廠來生產新種類的產,這是因為在抽象工廠角色中規定了所有可能被建立的產品集合,要支援新種類的產品就意味著要對該介面進行擴充套件,而這將涉及到對抽象工廠角色及其所有子類的修改,顯然會帶來較大的不便。 開閉原則的傾斜性(增加新的工廠和產品族容易,增加新的產品等級結構麻煩)
5.應用:
模式適用環境 在以下情況下可以使用抽象工廠模式:
一個系統不應當依賴於產品類例項如何被建立、組合和表達的細節,這對於所有型別的工廠模式都是重要的。 系統中有多於一個的產品族,而每次只使用其中某一產品族。 屬於同一個產品族的產品將在一起使用,這一約束必須在系統的設計中體現出來。 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現。
(1) Java SE AWT(抽象視窗工具包)
在Java語言的AWT(抽象視窗工具包)中就使用了抽象工廠模式,它使用抽象工廠模式來實現在不同的作業系統中應用程式呈現與所在作業系統一致的外觀介面。
(2) 在很多軟體系統中需要更換介面主題,要求介面中的按鈕、文字框、背景色等一起發生改變時,可以使用抽象工廠模式進行設計。
6.總結:
(1)、抽象工廠模式提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬於物件建立型模式。
(2)、抽象工廠模式包含四個角色:
抽象工廠用於宣告生成抽象產品的方法;
具體工廠實現了抽象工廠宣告的生成抽象產品的方法,生成一組具體產品,這些產品構成了一個產品族,每一個產品都位於某個產品等級結構中;
抽象產品為每種產品宣告介面,在抽象產品中定義了產品的抽象業務方法;
具體產品定義具體工廠生產的具體產品物件,實現抽象產品介面中定義的業務方法。
抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態。抽象工廠模式與工廠方法模式最大的區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則需要面對多個產品等級結構。
(3)、抽象工廠模式的主要優點是隔離了具體類的生成,使得客戶並不需要知道什麼被建立,而且每次可以通過具體工廠類建立一個產品族中的多個物件,增加或者替換產品族比較方便,增加新的具體工廠和產品族很方便;主要缺點在於增加新的產品等級結構很複雜,需要修改抽象工廠和所有的具體工廠類,對“開閉原則”的支援呈現傾斜性。
(4)、抽象工廠模式適用情況包括:一個系統不應當依賴於產品類例項如何被建立、組合和表達的細節;系統中有多於一個的產品族,而每次只使用其中某一產品族;屬於同一個產品族的產品將在一起使用;系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現。
抽象工廠中的方法對應產品等級結構,具體的工廠對應產品族。