主要參考《大話設計模式》css
前面介紹的工廠方法模式中考慮的是一類產品的生產,如畜牧場養動物、電視機廠生產電視等,然而,現實生活中,許多工廠是綜合型工廠,可以生產各種產品,如大學包括各個系。sql
抽象工廠模式,爲建立一組相關或相互依賴的對象提供一個接口,且無需指定它們的具體類。是全部形態的工廠模式中最爲抽象和最具通常性的一種形態。數據庫
在框架開發中,對於同一個ORM,假如剛開始開發時使用SQL Server數據庫,可是也但願可以鏈接Access數據庫,或其餘的數據庫(如MySql、Oracle等)。SQL Server在.net中使用的System.Data.SqlClient命名空間下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,而Access要用System.Data.Olede命名空間下的相應對象,咱們不可能修改命名空間,或者從新寫相同的業務代碼只是修改與數據庫相關的代碼,這就是兩倍的工做量。於是,針對相似問題,能夠採用抽象工廠模式解決。設計模式
好比,如今要在業務邏輯代碼類似的狀況下,將SqlServer數據庫改成使用Access數據庫。 以「新增用戶」和「獲取用戶」爲例給出最基本的數據庫訪問程序。框架
class User { private int _id; public int ID { get { return _id;} set { _id = value; } } private string _name; public string Name { get { return _name; } set { _name = value; } } } class SqlServer { public void insert(User user) { Console.WriteLine("在sqlserver中爲User表添加一條記錄"); } public void select(int id) { Console.WriteLine("在sqlserver中根據用戶id查找用戶"); } } static void Main(string[] args) { User user = new User(); SqlServer sql = new SqlServer(); sql.insert(user); sql.select(1); Console.Read(); }
運行結果以下:sqlserver
上述實現中,沒法靈活的把sqlserver數據庫替換成其餘數據庫,緣由就是SqlServer sql = new SqlServer()使得sql對象被框死在Sqlserver上,若是此處是靈活的(多態的)應用,在執行sql.insert(user)時,不須要關注數據庫究竟是sqlserver仍是access,所以,咱們能夠採用工廠方法模式進行封裝。工廠方法模式是定義一個用於建立對象的接口,讓子類決定實例化哪一個類。this
class User { private int _id; public int ID { get { return _id;} set { this._id = value; } } private string _name; public string Name { get { return _name; } set { this._name = value; } } } interface IUser { void Insert(User user); User GeUser(int id); } class SqlserverUser:IUser { public void Insert(User user) { Console.WriteLine("在Sqlserver中新增一個用戶"); } public User GeUser(int id) { Console.WriteLine("在sqlserver中獲取一個用戶"); return null; } } class AccessUser:IUser { public void Insert(User user) { Console.WriteLine("在Access中新增一個用戶"); } public User GeUser(int id) { Console.WriteLine("在Access中獲取一個用戶"); return null; } } interface IFactory { IUser CreateUser(); } class SqlserverFactory:IFactory { public IUser CreateUser() { return new SqlserverUser(); } } class AccessFactory:IFactory { public IUser CreateUser() { return new AccessUser(); } } static void Main(string[] args) { User user=new User(); IFactory factory=new SqlserverFactory(); IUser sqlUser = factory.CreateUser(); sqlUser.Insert(user); sqlUser.GeUser(1); Console.WriteLine("Hello World!"); }
上述爲使用工廠方法模式實現不一樣數據庫中Insert、GetUser方法的實現,該實現中抽象接口與接口相關聯,而不是與具體的類耦合,對代碼進行了解耦,極大增長了代碼的靈活性。在main方法中只須要根據本身的需求生成數據庫實例便可,加入須要使用access數據庫,只需main中修改成如下語句便可:spa
IFactory factory=new AccessFactory();
上述用工廠方法實現不一樣數據庫新增或獲取User表數據,雖然實現了具體類與類之間的耦合,但一個數據庫中會存在不少表,好比Department表,若是須要獲取Department數據,則須要新增一個Department、ServerDepartment、AccessDepartment 3個類並更改IFactory、SqlServerFactory、AccssFactory操作系統
其中,IDepartment接口,用於客戶端訪問,解除具體數據庫訪問的耦合。.net
//IDepartment接口,用於客戶端訪問,解除具體數據庫訪問的耦合。
interface IDepartment { void Insert(Department depement); User GeUser(int id); } class Department { private int _id; public int ID { get { return _id;} set { this._id = value; } } private string _name; public string Name { get { return _name; } set { this._name = value; } } }
//SqlserverDepartment類,用於訪問sqlserver的Department class SqlserverDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Sqlserver中新增一個部門"); } public Department GetDepartment(int id) { Console.WriteLine("在sqlserver中獲取一個部門"); return null; } }
//AccessDepartment類,用於訪問access數據庫的Department class AccessDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Access中新增一個部門"); } public Department GetDepartment(int id) { Console.WriteLine("在Access中獲取一個部門"); return null; } }
interface IFactory { IUser CreateUser(); IDepartment CreateDepartment(); } // AccessFactory,實現IFactory接口,實例化AccessUser和AccessDepartment class AccessFactory:IFactory { public IUser CreateUser() { return new AccessUser(); } public IDepartment CreateDepartment() { return new AccessDepartment(); } } // SqlserverFactory類,實現IFactory接口,實例化SqlserverUser和SqlserverDepartment class SqlserverFactory:IFactory { public IUser CreateUser() { return new SqlserverUser(); } public IDepartment CreateDepartment() { return new SqlserverDepartment(); } } static void Main(string[] args) { User user=new User(); Department dep=new Department(); //IFactory factory=new SqlserverFactory(); IFactory factory=new AccessFactory(); IUser sqlUser = factory.CreateUser(); sqlUser.Insert(user); sqlUser.GeUser(1); IDepartment id = factory.CreateDepartment(); id.Insert(dep); id.GetDepartment(1); Console.WriteLine("Hello World!"); }
客戶端只需肯定實例化哪一個數據庫訪問對象給factory。
只有一個User類和User操做類的時候,只須要工廠方法模式,但因爲數據庫中會有不少表,sqlserver和access又是兩個不一樣的分類,所以,該問題中涉及多個產品系列的問題,對其實現,採用了抽象工廠模式。
上圖中,AbstractProductA和AbstractProductB是兩個抽象產品,對應於第3.4節場景分析中的User類和Department類,它們又擁有本身不一樣的實現,所以,ProductA一、ProductA一、ProductB一、ProductB2就是對兩個抽象產品具體分類的實現,分別表明SqlserverUser、AccessUser、SqlserverDepartment、AccessDepartment。.IFactory做爲一個抽象工廠接口,應該包含實現建立產品的方法(如:CreateSqlServer,CreateAccess).而CreateFactory1和CreateFactory2則表明具體的工廠(如:SqlServerFactory,AccessFactory)。一般,會在客戶端建立具體工廠類的實例,這個工廠再建立具備特定實現的產品對象,即爲建立不一樣的產品對象,客戶端應使用不一樣的具體工廠。
例如一個應用,須要在三個不一樣平臺上運行:Windows、Linux、Android等,三個不一樣操做系統上的軟件功能、應用邏輯、UI都應該是很是相似,惟一不一樣的是調用不一樣的工廠方法,由不一樣的產品類去處理與操做系統交互的信息。
抽象工廠模式的優勢及缺點:
優勢:
缺點:
產品的擴展困難,如上例產品中須要添加一張表Project,此時須要增長IProject 、SqlServerProject、AccessProject,並更改IFactory、SqlServerFactory、AccssFactory,改動較大。所以,在使用抽象工廠模式時,產品的結構等級結構劃分很是重要。