抽象工厂的应用
抽象工廠的應用
?本文是描述了自己對設計模式的工廠的了解.肯定有錯誤和不足的地方,希望大家能給予支持和建議.
1.問題的引出
??? 在前面的Post中,我描述了.NET的反射在軟件設計中的應用.當這篇Post發(fā)表之后,有人認為用工廠來實現(xiàn)更合理一些。
??? 在這篇Post里,描述的是根據(jù)某些條件如何動態(tài)的創(chuàng)建一個類的實例(這些條件最常見的是從應用程序的配置文件里去讀取,比如Web項目,你可以從.config文件里去讀取),比如有一個類名為SqlDataProvider,我們就可以使用”SqlDataProvider”字符串來構造一個SqlDataProvider實例。這就用到了反射,具體實現(xiàn)方法,參看這篇Post。
?為什么要這樣去做呢?其中我提到了是為了更好的擴展應用程序,可以使應用程序更加靈活,比如哪天我得數(shù)據(jù)庫不是 Mircrosoft SQL Server,而是Oracle,怎么辦呢?很簡單,你只需修改一下你的配置文件,寫為“OracleDataProvider”即可,當然,你也必須在你的程序里實現(xiàn)這個類了。但是不管是SqlDataProvider,還是OracleDataProvider,都必這篇Post須繼承自DataProvider這個抽象類。
這里用的是反射,那還有沒有其他解決方案呢?
2 問題解決方案的提出
?? 顯然,解決方案是有都的,并且相當經典。 正如這篇Post的評論一樣,可以采用工廠類解決。所以這里我們就用工廠來解決,并且我也更傾向于這一種方法。
??首先,這種工廠真正稱為Abstract Factory,它是一種設計模式(Design pattern),是創(chuàng)建模式(Creational Pattern)的一種。既然是創(chuàng)建模式,首先應該明白什么是創(chuàng)建模式?請看GOF的原文(原書英文版,第81頁):
?Creational design patterns abstract the instantiation process. They help make a system independent of how its objects are created, composed, or represented. A class creational pattern uses inheritance to vary the class that’s instantiated, whereas an object creational pattern will delegate instantiated to another object.
?了解了創(chuàng)建模式后,讓我們了解Abstract Factory,還是利用GOF的原文解釋吧。第87頁:
? Intent
?Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
意思再清楚不過了。如果想得到更多信息,參考GOF的《Design Pattern》一書。
據(jù)上所說,我認為它提供了一個接口供創(chuàng)建相關的一組對象等。
結構如下:
?
下面是對應的實例:
?
很明顯,結構里的AbstractFactory就是WidgetFactory,ConcreteFactory1就是MotifWidgetFactory,
ConcreteFactory2就是PMWidgetFactory。ConcreteFactory1負責構造Motif的Window,
ConcreteFactory2構造PM的window,所謂各司其職呀。
我想根據(jù)上面的圖,我們對工廠模式有一個很好的了解了。
3 解決方案的一個實例
? 在我們學習.NET時,Microsoft提供了一個實例,那就是在Java世界和現(xiàn)在.NET陣營特有名的PetShop(版本是3.0以上)。在這個版本種,它提供了一DALFactory,不用看代碼,就知道它干了一些什么事情。DAL(Data Access Layer,數(shù)據(jù)訪問層),Factory,工廠。好了,我也不多說了。看看一下他的類圖吧。
?
?首先我們應該知道,PetShop的數(shù)據(jù)庫既可以是SQLServer,也可以是Oracle,所以才有了SQLServerDAL和OracleDAL。對于Account,在BLL(Business Logic Layer,業(yè)務邏輯層)里的Account類調用了DAL工廠的Account,想想DAL工廠是如何工作的。假設我們現(xiàn)在用的是SQL Server,我們肯定會用SQLServerDAL里的Account,而不是Oracle里的。問題這樣就來了,如何去創(chuàng)建這個對象呢?在前面提到,我們可以根據(jù)應用的程序的配置文件來創(chuàng)建。我們只需要說明我們現(xiàn)在使用的是SQL Server,其相應的是SQLServerDAL即可。仔細閱讀一下源代碼,發(fā)現(xiàn)它確實是這樣做的。現(xiàn)在以BLL的Account的SignIn方法為例,給出PetShop的源代碼:
?BLL的Account的SignIn();
????????? public AccountInfo SignIn(string userId, string password) {
?
??????????????????????????????????? // Validate input
??????????????????????????????????? if ((userId.Trim() == string.Empty) || (password.Trim() == string.Empty))
??????????????????????????????????????????????? return null;
?
??????????????????????????????????? // Get an instance of the account DAL using the DALFactory
??????????????????????????????????? IAccount dal = PetShop.DALFactory.Account.Create();
?
??????????????????????????????????? // Try to sign in with the given credentials
??????????????????????????????????? AccountInfo account = dal.SignIn(userId, password);
?
??????????????????????????????????? // Return the account
??????????????????????????????????? return account;
??????????????????????? }
?????????DALFactory.Account.Create()的源代碼:
??????????? public class Account
??????????? {
??????????????????????? public static PetShop.IDAL.IAccount Create()
??????????????????????? {??????????????????????????????????
??????????????????????????????????? /// Look up the DAL implementation we should be using
??????????????????????????????????? string path = System.Configuration.ConfigurationSettings.AppSettings["WebDAL"];
??????????????????????????????????? string className = path + ".Account";
?
??????????????????????????????????? // Using the evidence given in the config file load the appropriate assembly and class
??????????????????????????????????? return (PetShop.IDAL.IAccount) Assembly.Load(path).CreateInstance(className);
??????????????????????? }
??????????? }
注意
System.Configuration.ConfigurationSettings.AppSettings["WebDAL"];
這行代碼,它從配置文件離地到WebDAL的內容,即“PetShop.SQLServerDAL”,所以最后className是PetShop.SQLServerDAL.Account.這樣就創(chuàng)建了一個SQLServerDAL的實例,返回的確實IAccount對象,但是根據(jù)面向對象原理,最后調用的還是SQLServerDAL.Account.
好了,再給出另外一個實例:
?
與上面的類似,我就不再多說了。
4.Post的問題的解決
?了解了上面的原理,再加上PetShop的實例,我想解決上一篇Post的問題就不算太難了。下面給出設計圖.
?
5.需解決問題
1) 抽象類(Abstract Class)和接口(Interface)的區(qū)別
顯然,在設計模式中,抽象是非常重要的,這樣就需要用到抽象類和接口,那么這兩者有什么聯(lián)系和區(qū)別呢?希望大家可以提出意見和建議.
2)? Abstract Facotry和Factory Method的區(qū)別
這兩個設計模式之間既有相似之處又有不同之點,希望大家能說出其關系,使我們更加清楚的了解他們,了解設計模式的精髓.
真誠希望大家給出自己的看法.
?
總結
- 上一篇: VS2010中不可忽视的部分——VSTO
- 下一篇: ISA之三种客户端访问