明辉站/网站教程/内容

设计模式之Factory

网站教程2024-05-29 阅读
[摘要]定义:提供创建对象的接口.为何使用?工厂模式是我们最常用的模式了,著名的Jive论坛系统,就大量使用了工厂模式.为什么说工厂模式是最常用,因为工厂模式就相当于创建对象的new. 工厂模式就是用来创建对象的.比如我们有一个类Sample 我们要创建Sample的对象:Sample sample=ne...
定义:提供创建对象的接口.

为何使用?
工厂模式是我们最常用的模式了,著名的Jive论坛系统,就大量使用了工厂模式.

为什么说工厂模式是最常用,因为工厂模式就相当于创建对象的new. 工厂模式就是用来创建对象的.

比如我们有一个类Sample 我们要创建Sample的对象:

Sample sample=new Sample();

如果我们要在创建sample之前做点事情,比如,赋值等,可以使用Sample的构造函数:

Sample sample=new Sample(参数);

如果创建sample时做的事情不是如赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那明显的就违背了面向对象的原则.封装(Encapsulation)和分派(Delegation);

我们需要将创建实例的责任与使用实例的责任分开, 使得语句

Sample sample=new Sample(参数);

就是简单的责任:使用Sample这个实例;至于创建Sample的任务就交给了Factory工厂模式.

还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.

现在Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:

Sample mysample=new MySample();
Sample hissample=new HisSample();

随着项目的深入,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.

但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.

你会建立一个专门生产Sample实例的工厂:

public class Factory{

  public static Sample creator(){

  ....
  if (which==1)
    return new MySample();
  else if (which==2)
    return new HisSample();

  }

}




那么在你的程序中,如果要实例化MySample时.就使用

Sample sample=Factory.creator();

这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵.

好了,言归正传,既然不可避免使用factory,那我们就认识一下工厂模式.

如何使用?
工厂模式中有: 简单工厂 工厂方法(Factory Method) 抽象工厂(Abstract Factory).


上例中,我们使用的是简单工厂. 这几个模式没有很明显的区别,在我的概念中,简单工厂应该是只有一个工厂方法,如果我们创建对象的方法变得复杂了,我们就可能要将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现:



public abstract class Factory{

  public abstract Sample creator();


  public abstract Sample2 creator();

}

public class SimpleFactory extends Factory{

  public Sample creator(){
    ......
  }

  public Sample2 creator(){
    ......
  }


}

public class BombFactory extends Factory{

  public Sample creator(){
    ......
  }

  public Sample2 creator(){
    ......
  }



}




上例中我们只有一类产品接口 Sample , 工厂方法和抽象工厂可以创建多个产品接口的实例,比如Sample2 Sample3
FactoryMethod往往只是创建单个的实例。Abstract Factory创建一系列的实例组,这些实例彼此相关。

举例1

下图是抽象工厂图:


在这张图中, 有两类产品接口interface RAM 和interface CPU; 同时有两个创建方法:MacProducer和PCProducer,这两个创建方法中都有createCPU()和createRAM(),返回的实例对象组是CPU和RAM, 这是分别来自两类产品接口,表面彼此是相关的.因此它是抽象工厂.

举例2

我们以Jive的ForumFactory为例:

public abstract class ForumFactory {

  private static Object initLock = new Object();
  private static String className = "com.jivesoftware.forum.database.DbForumFactory";
  private static ForumFactory factory = null;

  public static ForumFactory getInstance(Authorization authorization) {
    //If no valid authorization passed in, return null.
    if (authorization == null) {
      return null;
    }
    //以下使用了Singleton 单态模式
    if (factory == null) {
      synchronized(initLock) {
        if (factory == null) {
            ......

          try {
              //动态转载类
              Class c = Class.forName(className);
              factory = (ForumFactory)c.newInstance();
          }
          catch (Exception e) {
              return null;
          }
        }
      }
    }


    //Now, 返回 proxy.用来限制授权对forum的访问
    return new ForumFactoryProxy(authorization, factory,
                    factory.getPermissions(authorization));
  }

  //真正创建forum的方法由继承forumfactory的子类去完成.
  public abstract Forum createForum(String name, String description)
  throws UnauthorizedException, ForumAlreadyExistsException;

  ....


}






因为现在的Jive是通过数据库系统存放论坛帖子等内容数据,如果有人要扩展为纯粹的文件系统存放的论坛帖子,这个工厂方法ForumFactory就提供了提供动态接口:

private static String className = "com.jivesoftware.forum.database.DbForumFactory";

你可以使用自己开发的创建forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.

在上面的一段代码中一共用了三种模式,除了工厂模式外,还有Singleton单态模式,以及proxy模式,proxy模式主要用来授权用户对forum的访问,因为访问forum有两种人:一个是注册用户 一个是游客guest,那么那么相应的权限就不一样,而且这个权限是贯穿整个系统的,因此建立一个proxy,类似网关的概念,可以很好的达到这个效果.

好了.经过上述简单描述,你对工厂模式应该有个简单的印象,如果你要钻研工厂模式,网络上有很多英文资料,不过我觉得过分钻研也没有必要,主要是使用实践,实际使用中工厂模式的变种很多,只要你知道这样一个大概思路,相信在实践中你会是工厂模式的设计创建高手!

……

相关阅读