問題:
Factory Method模式是為一類對象提供建立介面或延遲物件的建立到子類中實現。但是,我們在軟體系統中,經常面臨著“一系列相互依賴的對象”的建立工作,同時由於需求的變化,這“一系列相互依賴的對象”也要改變,如何應對這種變化呢?Abstract Factory模式是為建立一系列相關或依賴的對象提供建立介面(AbstractFactory),將一組產品的建立封裝到一個用於建立對象的類(ConcreteFactory)中(形成一個系列),維護這樣一個建立類總比使用Factory Method維護n多相關對象的建立過程(邏輯)要簡單的多,而且
Factory Method,沒有辦法保證“一系列相互依賴的對象”,的聯絡,沒有聯絡就不是“一系列相互依賴的對象”的對象了。
定義:
提供一個建立一系列相關或相互依賴對象的介面,而無需指定它們具體的類。抽象工廠(Abstract Factory)模式又稱為Kit模式,屬於對象建立型模式。
意圖:
為建立一系列(多組,多類)相關或依賴的對象提供建立介面(AbstractFactory),此介面不負責產品的建立不關心產品執行個體化細節。將一組產品的建立封裝到一個用於建立對象的類(ConcreteFactory)中使得系統
定義一個使用者建立對象的公用介面,此介面不負責產品的建立不關心產品執行個體化細節,而是將具體建立工作交給子類去做,這樣做的目的是將類的執行個體化操作延遲到子類中完成,即由子類來決定究竟應該執行個體化(建立)哪一個類,使得Factory 方法模式可以允許系統在不修改工廠角色的情況下引進新產品。
參與者:
•抽象工廠角色:
擔任這個角色的是Factory 方法模式的核心,它是與應用系統的商業邏輯無關的。通常使用介面或抽象類別實現。
•具體工廠角色:
這個角色直接在用戶端的調用下建立產品的執行個體。這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統的商業邏輯緊密相關的。通常使用具體的類實現。
•抽象產品角色:
擔任這個角色的類是抽象Factory 方法模式所建立的對象的父類,或它們共同擁有的介面。通常使用介面或抽象類別實現這一角色。
•具體產品角色:
抽象原廠模式所建立的任何產品對象都是某一具體產品類的執行個體。這是用戶端最終需要的東西。通常使用具體類實現這個角色。
UML圖:
執行個體說明:
諾基亞手機工廠
比如Nokia手機工廠,現在只生產N8,N9兩款手機,但是要根據不同國家的網路環境,生產支援不同網路系列的手機,根據不同網路生產工廠(GMS生產車間,CDMA生產車間)建立至此不同網路的所有Nokia手機(N8.N9),而且容易加入新的網路環境(如:WCDMA)手機的生產(不修改現有系統)。
uml圖:
代碼:
/// <summary>
/// N8手機抽象產品類
/// </summary>
public abstract class N8Phone
{
public abstract string PhoneName { get; }
public abstract string NetTypeName { get; }
}
/// <summary>
/// N9手機抽象產品類
/// </summary>
public abstract class N9Phone
{
public abstract string PhoneName { get; }
public abstract string NetTypeName { get; }
public abstract string GpsTypeName { get; }
}
/// <summary>
/// N8,GMS網路 手機具體類
/// </summary>
public class N8Phone_Gsm : N8Phone
{
public override string NetTypeName
{
get
{
return "我是GSM的";
}
}
public override string PhoneName
{
get
{
return "我是N8";
}
}
}
/// <summary>
/// N8,CDMA網路 手機具體類
/// </summary>
public class N8Phone_Cdma : N8Phone
{
public override string NetTypeName
{
get
{
return "我是CDMA的";
}
}
public override string PhoneName
{
get
{
return "我是N8";
}
}
}
/// <summary>
/// N9,GMS網路 手機具體類
/// </summary>
public class N9Phone_Gsm : N9Phone
{
public override string NetTypeName
{
get
{
return "我是Gms的";
}
}
public override string PhoneName
{
get
{
return "我是N9";
}
}
public override string GpsTypeName
{
get
{
return "RJT2";
}
}
}
/// <summary>
/// N9,CDMA網路 手機具體類
/// </summary>
public class N9Phone_Cdma : N9Phone
{
public override string NetTypeName
{
get
{
return "我是CDMA的";
}
}
public override string PhoneName
{
get
{
return "我是N9";
}
}
public override string GpsTypeName
{
get
{
return "RJT2";
}
}
}
/// <summary>
/// 手機生產抽象工廠類
/// </summary>
public interface IPhoneFactory
{
N8Phone CreateNokiaN8();
N9Phone CreateNokiaN9();
}
/// <summary>
/// GMS手機具體工廠類
/// </summary>
public class GmsFactory : IPhoneFactory
{
public N8Phone CreateNokiaN8()
{
return new N8Phone_Gsm();
}
public N9Phone CreateNokiaN9()
{
return new N9Phone_Gsm();
}
}
/// <summary>
/// CDMA手機具體工廠類
/// </summary>
public class CdmaFactory : IPhoneFactory
{
public N8Phone CreateNokiaN8()
{
return new N8Phone_Cdma();
}
public N9Phone CreateNokiaN9()
{
return new N9Phone_Cdma();
}
}
/// <summary>
/// 用戶端類
/// </summary>
class Program
{
public static void Main()
{
IPhoneFactory factory = new GmsFactory();
N8Phone phone1 = factory.CreateNokiaN8();
N9Phone phone2 = factory.CreateNokiaN9();
var s= phone1.NetTypeName;
}
}
優點:
•將客戶與具體產品類對象建立過程隔離,客戶通過抽象介面操縱執行個體,依賴於抽象類別(介面),耦合性低。
•由於客戶依賴與抽象類別,所以使得更換產品系列時變得非常容易,只須更改一下具體工廠名。
•系統能很好的應對“新系列”產品添加的擴充,無需修改現有代碼,只需加入相應的工廠類即可。
•一個系列的產品對象被約束在一起,能夠保證用戶端始終只使用一個系列產品中的對象,是非常實用的一種設計。如, GmsFactory工廠,不可能生產出N9Phone_Cdma手機。
缺點:
•Abstract Factory模式主要在於應對“新系列”的需求變動。缺點是難以應對“新對象”的需求變動。如果要支援新種類的產品,需要對工廠介面進行擴充,違反了開閉原則。
應用情景:
•系統有多於一個的系列,而只消費其中某一產系列。應對“多系列對象構建”的需求變化。“系列對象”指的是這項對象之間有相互依賴、或作用的關係。
•系統需要由一系列關聯的多個對象來構成,有關聯的多個對象需要一起應用並且它們的約束是強迫的,不可分離的