抽象工廠模式與工廠方法模式最大的區別在於:工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則針對的是多個產品等級結構。所以在抽象工廠模式中經常會用到產品族這一概念,它指的是位於不同的產品等級結構中,並且功能互相關聯的產品系列。
UML類圖:
其中類與對象的關係爲:
- AbstractFactory:抽象工廠
聲明生成抽象產品的方法
- ConcreteFactory:具體工廠
執行生成抽象產品的方法,生成一個具體的產品
- AbstractProduct:抽象產品
爲一種產品聲明接口
- Product:具體產品
定義具體工廠生產的具體產品的對象,實現產品接口
- Client:客戶
應用程序,使用抽象產品和抽象工廠生成對象。
爲了瞭解對象的創建和產品的生成過程,我們看一下抽象工廠典型應用的順序圖:
優勢劣勢:
抽象工廠模式主要優點是隔離了具體類的生成,使得客戶不需要知道什麼被創建了。由於這種隔離,使得更換一個具體的工廠變得相對容易,該模式符合GRASP純虛構的模式,實現了高內聚。主要缺點是,在添加新的產品對象時,難以擴展抽象工廠,因爲抽象工廠接口規定了所有可能被創建的產品集合,如果要支持新種類的產品,需要對工廠接口進行擴展,這就涉及到修改既有代碼,違反了開閉原則。
應用場景:
這個模式想必大家都十分熟悉,在開發中也會經常用到,比如說多數據庫支持,另外在下面的情景,可以考慮使用抽象工廠模式:
- 系統需要屏蔽有關對象如何創建、如何組織和如何表示
- 系統需要由關聯的多個對象來構成
- 有關聯的多個對象需要一起應用並且它們的約束是強迫的,不可分離的
- 提供一組對象而不顯示它們的實現過程,只顯示它們的接口
應用示例:
下面實現一個有信息保存和日誌保存的小模塊,要求該模塊可以方便的將保存的位置在數據庫和XML之間進行切換。
由於保存的位置不定,所以信息保存和日誌保存會針對不同的位置,有不同的處理形式,而針對一種保存方式而言,信息和日誌的保存又形成一族,針對這些特點,我們採用抽象工廠模式來實現該模塊。
首先,我們先將信息保存和日誌保存抽象出來:
{
public abstract void SaveMessage();
}
public abstract class LogDal
{
public abstract void SaveLog();
}
然後,我們根據不同的保存形式,分別實現抽象類:
{
public override void SaveMessage()
{
Console.WriteLine("信息保存到數據庫中");
}
}
public class XmlMessageDal : MessageDal
{
public override void SaveMessage()
{
Console.WriteLine("信息保存到XML中");
}
}
public class SqlLogDal : LogDal
{
public override void SaveLog()
{
Console.WriteLine("日誌保存到數據庫中");
}
}
public class XmlLogDal : LogDal
{
public override void SaveLog()
{
Console.WriteLine("日誌保存到XML中");
}
}
{
public abstract MessageDal CreateMessageDal();
public abstract LogDal CreateLogDal();
}
public class SqlFactory : AbstractFactory {
public override MessageDal CreateMessageDal()
{
return new SqlMessageDal();
}
public override LogDal CreateLogDal()
{
return new SqlLogDal();
}
}
public class XmlFactory : AbstractFactory {
public override MessageDal CreateMessageDal()
{
return new XmlMessageDal();
}
public override LogDal CreateLogDal()
{
return new XmlLogDal();
}
}
{
static void Main() {
AbstractFactory factory = new SqlFactory();
MessageDal msg = factory.CreateMessageDal();
LogDal log = factory.CreateLogDal();
msg.SaveMessage();
log.SaveLog();
factory = new XmlFactory();
msg = factory.CreateMessageDal();
log = factory.CreateLogDal();
msg.SaveMessage();
log.SaveLog();
Console.ReadLine();
}
}
至此我們的小模塊實現完成了,保存位置修改,只需生成不同的工廠實例就可以了。
實際的生產環境,我們肯定一般只需要保存到一個位置,上面的客戶端代碼爲了演示,將2個位置都保存了,代碼中,爲了切換到XML保存,我們還是修改了客戶端代碼,作爲一個有追求的碼農,這是我們不想看到的。所以,我們採用反射修改一下我們的客戶端調用代碼:
AbstractFactory factory = (AbstractFactory)Assembly.Load("Gof").CreateInstance("Gof.AbstractFactory.SqlFactory");
MessageDal msg = factory.CreateMessageDal();
LogDal log = factory.CreateLogDal();
msg.SaveMessage();
log.SaveLog();
Console.ReadLine();
}
由於創建實際工廠採用了反射形式,所以現在我們可以通過配置文件決定我們的保存位置了,客戶端代碼也就無需修改了。這裏不在贅述...