抽象工厂的应用

 

抽象工厂的应用

 本文是描述了自己对设计模式的工厂的了解.肯定有错误和不足的地方,希望大家能给予支持和建议.

1.问题的引出

    在前面的Post,我描述了.NET的反射在软件设计中的应用.当这篇Post发表之后,有人认为用工厂来实现更合理一些。

    在这篇Post里,描述的是根据某些条件如何动态的创建一个类的实例(这些条件最常见的是从应用程序的配置文件里去读取,比如Web项目,你可以从.config文件里去读取),比如有一个类名为SqlDataProvider,我们就可以使用”SqlDataProvider”字符串来构造一个SqlDataProvider实例。这就用到了反射,具体实现方法,参看这篇Post

 为什么要这样去做呢?其中我提到了是为了更好的扩展应用程序,可以使应用程序更加灵活,比如哪天我得数据库不是 Mircrosoft SQL Server,而是Oracle,怎么办呢?很简单,你只需修改一下你的配置文件,写为“OracleDataProvider”即可,当然,你也必须在你的程序里实现这个类了。但是不管是SqlDataProvider,还是OracleDataProvider,都必这篇Post须继承自DataProvider这个抽象类。

这里用的是反射,那还有没有其他解决方案呢?

2 问题解决方案的提出

   显然,解决方案是有都的,并且相当经典。 正如这篇Post的评论一样,可以采用工厂类解决。所以这里我们就用工厂来解决,并且我也更倾向于这一种方法。

  首先,这种工厂真正称为Abstract Factory,它是一种设计模式(Design pattern,是创建模式(Creational Pattern)的一种。既然是创建模式,首先应该明白什么是创建模式?请看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.

 了解了创建模式后,让我们了解Abstract Factory,还是利用GOF的原文解释吧。第87
  Intent

 Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

意思再清楚不过了。如果想得到更多信息,参考GOF的《Design Pattern》一书。

据上所说,我认为它提供了一个接口供创建相关的一组对象等。

结构如下

 

下面是对应的实例:

 

很明显,结构里的AbstractFactory就是WidgetFactoryConcreteFactory1就是MotifWidgetFactory

ConcreteFactory2就是PMWidgetFactoryConcreteFactory1负责构造MotifWindow

ConcreteFactory2构造PMwindow,所谓各司其职呀。

我想根据上面的图,我们对工厂模式有一个很好的了解了。

3 解决方案的一个实例

  在我们学习.NET时,Microsoft提供了一个实例,那就是在Java世界和现在.NET阵营特有名的PetShop(版本是3.0以上)。在这个版本种,它提供了一DALFactory,不用看代码,就知道它干了一些什么事情。DALData Access Layer,数据访问层),Factory,工厂。好了,我也不多说了。看看一下他的类图吧。

  

首先我们应该知道,PetShop的数据库既可以是SQLServer,也可以是Oracle,所以才有了SQLServerDALOracleDAL。对于Account,在BLLBusiness Logic Layer,业务逻辑层)里的Account类调用了DAL工厂的Account,想想DAL工厂是如何工作的。假设我们现在用的是SQL Server,我们肯定会用SQLServerDAL里的Account,而不是Oracle里的。问题这样就来了,如何去创建这个对象呢?在前面提到,我们可以根据应用的程序的配置文件来创建。我们只需要说明我们现在使用的是SQL Server,其相应的是SQLServerDAL即可。仔细阅读一下源代码,发现它确实是这样做的。现在以BLLAccountSignIn方法为例,给出PetShop的源代码:
 BLLAccountSignIn();
          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”,所以最后classNamePetShop.SQLServerDAL.Account.这样就创建了一个SQLServerDAL的实例,返回的确实IAccount对象,但是根据面向对象原理,最后调用的还是SQLServerDAL.Account.

好了,再给出另外一个实例:

 

与上面的类似,我就不再多说了。

4.Post的问题的解决

 了解了上面的原理,再加上PetShop的实例,我想解决上一篇Post的问题就不算太难了。下面给出设计图.

 

5.需解决问题

1) 抽象类(Abstract Class)和接口(Interface)的区别

显然,在设计模式中,抽象是非常重要的,这样就需要用到抽象类和接口,那么这两者有什么联系和区别呢?希望大家可以提出意见和建议.

2)  Abstract FacotryFactory Method的区别

这两个设计模式之间既有相似之处又有不同之点,希望大家能说出其关系,使我们更加清楚的了解他们,了解设计模式的精髓.

真诚希望大家给出自己的看法.

 

posted @ 2005-04-22 09:16  张太国  阅读(4411)  评论(11编辑  收藏  举报