工廠模式之抽象工廠

主要參考《大話設計模式》css

1. 引入

  前面介紹的工廠方法模式中考慮的是一類產品的生產,如畜牧場養動物、電視機廠生產電視等,然而,現實生活中,許多工廠是綜合型工廠,可以生產各種產品,如大學包括各個系。sql

2. 定義

  抽象工廠模式,爲建立一組相關或相互依賴的對象提供一個接口,且無需指定它們的具體類。是全部形態的工廠模式中最爲抽象和最具通常性的一種形態。數據庫

3. 場景實現

3.1 場景描述 

  在框架開發中,對於同一個ORM,假如剛開始開發時使用SQL Server數據庫,可是也但願可以鏈接Access數據庫,或其餘的數據庫(如MySql、Oracle等)。SQL Server在.net中使用的System.Data.SqlClient命名空間下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,而Access要用System.Data.Olede命名空間下的相應對象,咱們不可能修改命名空間,或者從新寫相同的業務代碼只是修改與數據庫相關的代碼,這就是兩倍的工做量。於是,針對相似問題,能夠採用抽象工廠模式解決。設計模式

  好比,如今要在業務邏輯代碼類似的狀況下,將SqlServer數據庫改成使用Access數據庫。 以「新增用戶」和「獲取用戶」爲例給出最基本的數據庫訪問程序。框架

3.2 最基本的數據訪問程序

  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

3.3 使用工廠方法模式的數據訪問程序

3.3.1 UML圖

 

3.3.2 代碼實現

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();

3.4 使用抽象工廠實現

  上述用工廠方法實現不一樣數據庫新增或獲取User表數據,雖然實現了具體類與類之間的耦合,但一個數據庫中會存在不少表,好比Department表,若是須要獲取Department數據,則須要新增一個Department、ServerDepartment、AccessDepartment 3個類並更改IFactory、SqlServerFactory、AccssFactory操作系統

3.4.1 UML圖

  其中,IDepartment接口,用於客戶端訪問,解除具體數據庫訪問的耦合。.net

3.4.2 代碼實現  

//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又是兩個不一樣的分類,所以,該問題中涉及多個產品系列的問題,對其實現,採用了抽象工廠模式。

4. 抽象工廠模式UML圖

 

  上圖中,AbstractProductA和AbstractProductB是兩個抽象產品,對應於第3.4節場景分析中的User類和Department類,它們又擁有本身不一樣的實現,所以,ProductA一、ProductA一、ProductB一、ProductB2就是對兩個抽象產品具體分類的實現,分別表明SqlserverUser、AccessUser、SqlserverDepartment、AccessDepartment。.IFactory做爲一個抽象工廠接口,應該包含實現建立產品的方法(如:CreateSqlServer,CreateAccess).而CreateFactory1和CreateFactory2則表明具體的工廠(如:SqlServerFactory,AccessFactory)。一般,會在客戶端建立具體工廠類的實例,這個工廠再建立具備特定實現的產品對象,即爲建立不一樣的產品對象,客戶端應使用不一樣的具體工廠。

5. 其餘應用場景

  例如一個應用,須要在三個不一樣平臺上運行:Windows、Linux、Android等,三個不一樣操做系統上的軟件功能、應用邏輯、UI都應該是很是相似,惟一不一樣的是調用不一樣的工廠方法,由不一樣的產品類去處理與操做系統交互的信息。

 6. 總結

   抽象工廠模式的優勢及缺點:

  優勢:

  • (1)易於交換產品系列(如:上例中,使用SqlServer數據庫仍是Access數據庫只需改變IFactury factory = new AccessFactory();/便可),只需改變具體工廠便可使用不一樣的產品配置
  • (2)具體的建立實例過程與客戶端分離。客戶端是經過抽象接口操做實例,產品的具體類名也被具體工廠的實現分離,不會出如今客戶代碼中。

   缺點:

  產品的擴展困難,如上例產品中須要添加一張表Project,此時須要增長IProject 、SqlServerProject、AccessProject,並更改IFactory、SqlServerFactory、AccssFactory,改動較大。所以,在使用抽象工廠模式時,產品的結構等級結構劃分很是重要。

相關文章
相關標籤/搜索