抽象工廠模式,這裏借鑑了 2 篇文章。
文章一:java版本的例子:
抽象工廠模式是對象的創建模式,它是工廠方法模式的進一步推廣。
抽象工廠模式可以向客戶端提供一個接口,使得客戶端在不必指定具體產品類型的情況下,創建多個產品族中的產品,這就是抽象工廠模式的用意。
每個模式都是針對一定問題的解決方案,抽象工廠模式面對的問題是多個產品等級結構的系統設計。
抽象工廠模式中涉及到兩個概念:產品族和產品等級結構
產品族:是指位於不同產品等級結構中,功能相關聯的產品組成的家族,比如:麥當勞和肯德基,這兩個產品有不同的分店,北京有家麥當勞和肯德基店,上海也有家,北京的麥當勞和北京的肯德基組成一個產品族。
產品等級結構:北京的麥當勞和上海的麥當勞組成了一個產品等級結構。
示意圖如下:
抽象工廠模式的結構
涉及到四個角色
1)抽象工廠角色:是抽象工廠方法模式的核心,與應用系統的商業邏輯無關。通過使用java接口或抽象類實現,而 所有的具體工廠類必須實現這個角色。
2)具體工廠角色:這個角色直接在客戶端的調用下創建產品的實例,這個角色含有選擇合適的產品對象的邏輯,通常使用
java類實現這個角色。
3)抽象產品角色:所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口,通常由java接口或抽象
類實現。
4)具體產品角色:抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例,這是客戶端最終需要的,通常由 java類實現.
/**
* 抽象產品角色
* @author Administrator
*
*/
public interface KfcBread
{
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class ShangHaiKfc implements KfcBread
{
public ShangHaiKfc()
{
System.out.println("肯德基出生地:上海");
}
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class BeiJingKfc implements KfcBread
{
public BeiJingKfc()
{
System.out.println("肯德基出生地:北京");
}
}
/**
* 抽象產品角色
* @author Administrator
*
*/
public interface McdBread
{
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class ShangHaiMcd implements McdBread
{
public ShangHaiMcd()
{
System.out.println("麥當勞出生地:上海");
}
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class BeiJingMcd implements McdBread
{
public BeiJingMcd()
{
System.out.println("麥當勞出生地:北京");
}
}
/**
* 抽象工廠角色
* @author Administrator
*
*/
public interface Toaster
{
KfcBread toastKFC();
McdBread toastMCD();
}
/**
* 具體工廠角色
* @author Administrator
*
*/
public class ShangHaiToaster implements Toaster
{
public KfcBread toastKFC()
{
return new ShangHaiKfc();
}
public McdBread toastMCD()
{
return new ShangHaiMcd();
}
}
/**
* 具體工廠角色
* @author Administrator
*
*/
public class BeiJingToaster implements Toaster
{
public KfcBread toastKFC()
{
return new BeiJingKfc();
}
public McdBread toastMCD()
{
return new BeiJingMcd();
}
}
/**
* 測試類
* @author Administrator
*
*/
public class client
{
public static void main(String[] args)
{
Toaster t1 = new BeiJingToaster();
Toaster t2 = new ShangHaiToaster();
McdBread mcd1 = t1.toastMCD();
McdBread mcd2 = t2.toastMCD();
KfcBread kfc1 = t1.toastKFC();
KfcBread kfc2 = t2.toastKFC();
}
}
* 抽象產品角色
* @author Administrator
*
*/
public interface KfcBread
{
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class ShangHaiKfc implements KfcBread
{
public ShangHaiKfc()
{
System.out.println("肯德基出生地:上海");
}
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class BeiJingKfc implements KfcBread
{
public BeiJingKfc()
{
System.out.println("肯德基出生地:北京");
}
}
/**
* 抽象產品角色
* @author Administrator
*
*/
public interface McdBread
{
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class ShangHaiMcd implements McdBread
{
public ShangHaiMcd()
{
System.out.println("麥當勞出生地:上海");
}
}
/**
* 具體產品角色
* @author Administrator
*
*/
public class BeiJingMcd implements McdBread
{
public BeiJingMcd()
{
System.out.println("麥當勞出生地:北京");
}
}
/**
* 抽象工廠角色
* @author Administrator
*
*/
public interface Toaster
{
KfcBread toastKFC();
McdBread toastMCD();
}
/**
* 具體工廠角色
* @author Administrator
*
*/
public class ShangHaiToaster implements Toaster
{
public KfcBread toastKFC()
{
return new ShangHaiKfc();
}
public McdBread toastMCD()
{
return new ShangHaiMcd();
}
}
/**
* 具體工廠角色
* @author Administrator
*
*/
public class BeiJingToaster implements Toaster
{
public KfcBread toastKFC()
{
return new BeiJingKfc();
}
public McdBread toastMCD()
{
return new BeiJingMcd();
}
}
/**
* 測試類
* @author Administrator
*
*/
public class client
{
public static void main(String[] args)
{
Toaster t1 = new BeiJingToaster();
Toaster t2 = new ShangHaiToaster();
McdBread mcd1 = t1.toastMCD();
McdBread mcd2 = t2.toastMCD();
KfcBread kfc1 = t1.toastKFC();
KfcBread kfc2 = t2.toastKFC();
}
}
這段代碼中有個問題:就是在具體的工廠中增加相應的具體產品的話,要去修改具體工廠中的代碼,這和軟件開發的“接納增加,避免修改”是相矛盾的。
文章二:.Net版本。
現在有這樣一個需求:
老闆:我要做一種產品。
程序員:我們沒有考慮,直接做了一個產品類(ProductA1)和 產品線ProductFactory1。
老闆:我還要再做另一種產品。
程序員:我們沒有考慮,又做了一個產品類(ProductA2)。
老闆:我還要再做另一種產品。
程序員:我們沒有考慮,又做了一個產品類(ProductB1)。
老闆:我還要再做另一種產品。
程序員:憤怒,又做了一個產品類(ProductB2)。
老闆:使用中。。。
程序員:怕了他了,所以做了一個擴展, 抽象出來 AbstractProductA AbstractProductB。
老闆:經過使用我們發現要新增我們的產品線來提高效率
程序員:沒考慮,怎加了產品線ProductFactory2。
老闆:經過我們的考慮兩條產品線還是不能滿足要求。
程序員:怕了他了,所以做了一個擴展 抽象出來AbstractFactory。
到現在我們看似完成了,其實是一團糟,讓我們看看都做了什麼,當我們產品類需要增加一個方法時,需要改寫產品類的同時
要怎加產品線方法和產品線接口,更遭的是要增加產品線。依賴關係依然沒有太大改善。
現在我們解決它:
程序員:我們沒有考慮,直接做了一個產品類(ProductA1)和 產品線ProductFactory1。
老闆:我還要再做另一種產品。
程序員:我們沒有考慮,又做了一個產品類(ProductA2)。
老闆:我還要再做另一種產品。
程序員:我們沒有考慮,又做了一個產品類(ProductB1)。
老闆:我還要再做另一種產品。
程序員:憤怒,又做了一個產品類(ProductB2)。
老闆:使用中。。。
程序員:怕了他了,所以做了一個擴展, 抽象出來 AbstractProductA AbstractProductB。
老闆:經過使用我們發現要新增我們的產品線來提高效率
程序員:沒考慮,怎加了產品線ProductFactory2。
老闆:經過我們的考慮兩條產品線還是不能滿足要求。
程序員:怕了他了,所以做了一個擴展 抽象出來AbstractFactory。
到現在我們看似完成了,其實是一團糟,讓我們看看都做了什麼,當我們產品類需要增加一個方法時,需要改寫產品類的同時
要怎加產品線方法和產品線接口,更遭的是要增加產品線。依賴關係依然沒有太大改善。
現在我們解決它:
實現:下面是一個接口的例子(我懶得改成抽象類,道理是一樣的)。
interface IFactory
{
object CreateProduct(string className);
}
class ProductFactory:IFactory
{
object CreateProduct(string className)
{
string path = "*.dll";
return Assembly.Load(path).CreateInstance(path + className);
}
}
dll內容:
public interface IProductA { }
public class ProductA1 : IProductA { }
public class ProductA2 : IProductA { }
public interface IProductB { }
public class ProductB1 : IProductB { }
public class ProductB2 : IProductB { }
static void Main(string[] args)
{
IFactory factory = new ProductFactory();
IProductA productA = (IProductA)factory.CreateProduct("ClassName");
}
{
object CreateProduct(string className);
}
class ProductFactory:IFactory
{
object CreateProduct(string className)
{
string path = "*.dll";
return Assembly.Load(path).CreateInstance(path + className);
}
}
dll內容:
public interface IProductA { }
public class ProductA1 : IProductA { }
public class ProductA2 : IProductA { }
public interface IProductB { }
public class ProductB1 : IProductB { }
public class ProductB2 : IProductB { }
static void Main(string[] args)
{
IFactory factory = new ProductFactory();
IProductA productA = (IProductA)factory.CreateProduct("ClassName");
}
這裏也有個地方需要補充下:
當有多個產品工廠的時候,只需要增加相應的工廠類,同事增加相應的dll文件(相應的產品類別[產品接口] 和 產品具體類)。