抽象工廠模式

解讀設計模式----抽象工廠模式(AbstractFactory Pattern)

一、模式描述
      我的程序中有需要一系列的對象,比如我們要吃一碗米飯(Rice),要喝一杯咖啡(Coffee)......,要想利用他們,我們就必須在程序中根據用戶要求,然後一個個調用 new 操作符來生成他們,這樣客戶程序就要知道相應的類的信息,生成的代碼顯然不夠靈活。那麼我們可以在代碼中不利用具體的類,而只是說明我們需要什麼,然後就能夠得到我們想要的對象呢?  
      這當然是可以的,根據GOF在《設計模式》一書裏介紹,要創建對象這樣的工作應該是屬於創建型模式完成的。熟悉各種設計模式意圖的朋友就會很快得出結論:“提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類”,至少“無需指定它們具體的類”符合我們的要求。OK,這就是抽象工廠模式的意圖。

二、模式意圖
      提供一個創建一系列相關或相互依賴對象的接口,而不需指定他們具體的類。

三、模式UML圖:                   
               
四、模式參與者
  抽象工廠(Abstract Factory)角色:擔任這個角色的是工廠方法模式的核心,它是與應用系統商業邏輯無關的。 
  具體工廠(Concrete Factory)角色:這個角色直接在客戶端的調用下創建產品的實例。這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統的商業邏輯緊密相關的。
  抽象產品(Abstract Product)角色:擔任這個角色的類是工廠方法模式所創建的對象的父類,或它們共同擁有的接口。
  具體產品(Concrete Product)角色:抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例。這是客戶端最終需要的東西,其內部一定充滿了應用系統的商業邏輯。

五、模式與反射
     利用設計模式可以使我們的代碼更靈活,更容易擴展,更容易維護。各種面向對象的程序設計語言都提供了基本相同的機制:比如類、繼承、派生、多態等等。但是又有各自的特色,C# 中的反射機制便是一個很重要的工具,好好地利用就可以在實際中發揮很大的作用。
     反射是.NET Framework中的一個非常重要的特性。相信絕大多數的朋友都對其有所瞭解或是已經熟練的應用這項技術。我們需要根據需求去動態的創建一對象的實例,在程序設計中,通常我們會爲了解耦合,把接口的實現對象寫入配置文件,讓工廠自己去一個特定的地方(配置文件)找他應該要實例化的對象(接口的實現對象),通過這樣來實現“依賴注入(Dependency Injection)”。
     本來“依賴注入”需要專門的IOC容器提供,比如Spring.net,Castle這類似的框架產品。而在抽象工廠模式的應用中顯然沒有這麼麻煩,通常的實現就是使用.NET技術‘反射’就可以了。下面是反射的兩種常見應用:
應用一:
         Activator.CreateInstance("類型");
應用二:
         Assembly.Load("程序集名稱").CreateInstance("命名空間.類名稱");


六、抽象工廠的簡單實現

Entity Code

 

複製代碼
 1namespace DesignPattern.AbstractFactory
 2{
 3    /// <summary>
 4    /// 抽象產品角色
 5    /// </summary>

 6    public interface INews
 7    {
 8        void Insert(News news);
 9        News QueryById(int newsId);
10    }

11
12    /// <summary>
13    /// 具體產品角色
14    /// </summary>

15    public class NewsSql:INews
16    {
17        public void Insert(News news)
18        {
19            Console.WriteLine("插入新聞到SQL數據庫");
20        }

21
22        public News QueryById(int newsId)
23        {
24            return new News(1"Hello"" Hello C#!""beniao");
25        }

26    }

27
28    /// <summary>
29    /// 具體產品角色
30    /// </summary>

31    public class NewsAccess : INews
32    {
33        public void Insert(News news)
34        {
35            Console.WriteLine("插入新聞到Access數據庫");
36        }

37
38        public News QueryById(int newsId)
39        {
40            return new News(1"Hello"" Hello C#!""beniao");
41        }

42    }

43}
複製代碼

 

複製代碼
 1namespace DesignPattern.AbstractFactory
 2{
 3    /// <summary>
 4    /// 抽象產品角色
 5    /// </summary>

 6    public interface IUser
 7    {
 8        void Insert(User user);
 9        User QueryById(int userId);
10    }

11
12    /// <summary>
13    /// 具體產品角色
14    /// </summary>

15    public class UserSql:IUser
16    {
17        public void Insert(User user)
18        {
19            Console.WriteLine("Insert SQL OK!");
20        }

21
22        public User QueryById(int userId)
23        {
24            return new User(1"beniao""22");
25        }

26    }

27
28    /// <summary>
29    /// 具體產品角色
30    /// </summary>

31    public class UserAccess : IUser
32    {
33        public void Insert(User user)
34        {
35            Console.WriteLine("Insert Access OK!");
36        }

37
38        public User QueryById(int userId)
39        {
40            return new User(2"beniao""23");
41        }

42    }

43}
複製代碼

 

複製代碼
 1namespace DesignPattern.AbstractFactory
 2{
 3    /// <summary>
 4    /// 工廠角色(根據配置文件來確定創建何種對象)
 5    /// </summary>

 6    public class DataAccess
 7    {
 8        public static IUser CreateUser()
 9        {
10            string obj = ConfigurationManager.AppSettings["usersql"];
11            return (IUser)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
12        }

13
14        public static INews CreateNews()
15        {
16            string obj = ConfigurationManager.AppSettings["newssql"];
17            return (INews)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
18        }

19    }

20***********************************************************************************
21    /// <summary>
22    /// 如果根據GOF的定義及UML圖,此爲抽象工廠角色
23    /// </summary>

24    public class Factory
25    {
26        public  virtual IUser CreateUser() 
27        {
28            return null;
29        }

30
31        public  virtual INews CreateNews()
32        {
33            return null;
34        }

35    }

36
37    /// <summary>
38    /// 具體的工廠角色
39    /// </summary>

40    public class SqlFactory:Factory
41    {
42        public override IUser CreateUser()
43        {
44            string obj = ConfigurationManager.AppSettings["usersql"];
45            return (IUser)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
46        }

47
48        public override INews CreateNews()
49        {
50            string obj = ConfigurationManager.AppSettings["newssql"];
51            return (INews)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
52        }

53    }

54
55    /// <summary>
56    /// 具體的工廠角色
57    /// </summary>

58    public class AccessFactory : Factory
59    {
60        public override IUser CreateUser()
61        {
62            string obj = ConfigurationManager.AppSettings["useracc"];
63            return (IUser)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
64        }

65
66        public override INews CreateNews()
67        {
68            string obj = ConfigurationManager.AppSettings["newsacc"];
69            return (INews)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
70        }
 
71    }

72}
複製代碼

 

複製代碼
 1namespace DesignPattern.AbstractFactory
 2{
 3    class Program
 4    {
 5        static void Main(string[] args)
 6        {
 7            IUser user = DataAccess.CreateUser();
 8            user.Insert(null);
 9
10            INews news = DataAccess.CreateNews();
11            news.Insert(null);
12
13            //******************GOF************************
14
15            Factory factory = new SqlFactory();
16            factory.CreateNews().Insert(null);
17            factory.CreateUser().Insert(null);
18
19            factory = new AccessFactory();
20            factory.CreateNews().Insert(null);
21            factory.CreateUser().Insert(null);
22        }

23    }

24}
複製代碼

          
七、.NET 2.0中的抽象工廠模式
     .NET 2.0相比.NET 1.1有很大的改進,就在ADO.NET上來說吧,提供了一套新的操作接口。下面我就簡單的介紹下這套接口的設計,在System.Date下提供了IDbConnection IDbCommandIDbDataAdapter以及IDbTransaction這樣一系列接口,通過ProviderFactory來完成具體實現對象的創建,這裏就是抽象工廠模式的一個應用。示意性代碼:

複製代碼
 1public IDbConnection CreateConnection()
 2{
 3    IDbConnection conn = null;
 4    try
 5    {
 6        conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[(int)_provider]);
 7    }

 8    catch(TargetInvocationException e)
 9    {
10        throw new Exception(e.Message);
11    }

12    return conn;
13}

14
15public IDbConnection CreateConnection(string connectionString)
16{
17    IDbConnection conn = null;
18    object[] param ={ connectionString };
19    try
20    {
21        conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[(int)_provider], param);
22    }

23    catch (TargetInvocationException e)
24    {
25        throw new Exception(e.Message);
26    }

27    return conn;
28}
複製代碼

     在_connectionTypes數組裏存放的是IDbConnection接口的具體實現類型,如下:

private static Type[] _connectionTypes = new Type[] typeof(OleDbConnection), typeof(SqlConnection) };

由於Command,DataAdapter等對象的代碼都和上面很相似,這裏就不作過多解釋,我把代碼貼到下面,有興趣的看看:

ProviderFactory

      關於.NET 2.0的這一知識點不瞭解的朋友可以下載Web Cast課程進行學習。本文就簡單的介紹這些。

七、.NET 2.0中的新ADO.NET操作接口應用示例
     建立一ASP.NET網站項目,在默認的Default.aspx裏放置一個GridView控件便OK。這裏以MSSQL 2000裏的Northwind數據庫作爲示例數據庫,查詢出訂單表的數據呈現在aspx頁面上,進入後臺代碼文件(.cs文件):

複製代碼
 1public partial class _Default : System.Web.UI.Page 
 2{
 3    protected void Page_Load(object sender, EventArgs e)
 4    {
 5        string connectionString="Data Source=.;Initial Catalog=Northwind;user id=sa;password=;";
 6        string cmdText = "select * from orders";
 7
 8        ProviderFactory factory = new ProviderFactory(ProviderType.SqlClient);
 9        IDbConnection conn = factory.CreateConnection(connectionString);
10        IDbDataAdapter sda = factory.CreateDataAdapter(cmdText, conn);
11        DataSet ds = new DataSet();
12        sda.Fill(ds);
13        this.GridView1.DataSource = ds.Tables[0];
14        this.GridView1.DataBind();
15    }

16}
複製代碼

      ProviderFactory擔任着工廠的角色,負責創建如IDbConnection、IDbCommand等一系列的產品。如上,我們拿到了工廠角色,通過工廠角色的CreateConnection就創建到了一個基於抽象產品角色IDbConnection接口的實現對象(具體是什麼實現對象我們暫不管)。
     .NET 2.0提供了這一套操作接口,對於程序實現上就更加靈活了,更是強調了使用“依賴接口/抽象編程”的思想。 

示例程序代碼下載
注:轉載請註明出處:http://beniao.cnblogs.com/ 或  http://www.cnblogs.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章