[Design Pattern] The Factory Pattern

本文详细介绍了工厂模式中的简单工厂、工厂模式和抽象工厂的概念,并通过Thinkpad笔记本生产线的例子展示了三种模式的应用场景及其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:

简单工厂和工厂模式:http://www.blogjava.net/flyingis/archive/2007/06/17/124542.html 

抽象工厂:http://www.cnblogs.com/Reeezak/archive/2005/10/23/260493.html


工厂模式用于创建实例对象,我们只需告诉工厂需要的对象有什么特点,就能得到所需的结果,而不用去关心怎么创建对象,工厂类似于黑盒,黑盒里面关于对象生产的细节不是关注的重点。

    工厂模式分为:简单工厂模式、工厂模式、抽象工厂模式。

    例子:Thinkpad笔记本生产线。

    简单工厂模式

public  class SimpleThinkpadTFactory  {
  public ThinkpadT produceThinkpadT(String type) {
    ThinkpadT thinkpadT = null;
    // 根据不同的类型创建不同的Thinkpad
    if (type.equals("t60")) {
      thinkpadT = new ThinkpadT60();
    }
 else if (type.equals("t60p")) {
      thinkpadT = new ThinkpadT60p();
    }

  return thinkpadT;
  }

}


public  class ThinkpadTStore  {
  SimpleThinkpadTFactory factory;
  public ThinkpadTStore(SimpleThinkpadFactory factory) {
    this.factory = factory;
  }


  public ThinkpadT buyThinkpadT(String type) {
    ThinkpadT thinkpadT;
    // 不再根据不同条件,使用new去创建对象
    thinkpadT = factory.produceThinkpadT(type);
    return thinkpadT;
  }

}


    从上例可以看出,SimpleThinkpadTFactory只需知道用户需要什么型号的Thinkpad T系列的电脑,就能返回该型号Thinkpad的对象,避免了在ThinkpadTStore中书写冗长的代码,降低了代码的耦合度。但是在SimpleThinkpadTFactory中,一旦机器的型号分的特别细、特别多,如T42/T43/T60/T42p/T43p/T60p等等,就需要维护大量的"if else",这显然不是我们想看到的,这里我们引入工厂模式。

    工厂模式

public  abstract  class ThinkpadTStore  {
  public ThinkpadT buyThinkpadT(String type) {
    ThinkpadT thinkpadT;
    thinkpadT = produceThinkpadT(type);
    return thinkpadT;
  }

  // 单独抽取出工厂方法,abstract类型,需要在子类中实现
  abstract produceThinkpadT(String type);
}


public  class ThinkpadT43Store  extends ThinkpadTStore  {
  ThinkpadT produceThinkpadT(String type) {
    if (type.equals("T43")) {
      return new ThinpadT43();
    }
 else if (type.equals("T43p")) {
      return new ThinkpadT43p();
    }
 else return null;
  }

}


public  class ThinkpadT60Store  extends ThinkpadTStore  {
  ThinkpadT produceThinkpadT(String type) {
    if (type.equals("T60")) {
      return new ThinpadT60();
    }
 else if (type.equals("T60p")) {
      return new ThinkpadT60p();
    }
 else return null;
  }

}


    具体执行代码:

public  class ThinpadTest  {
  public static void main(String[] args) {
    ThinkpadTStore thinkpadT43Store = new ThinkpadT43Store();
    ThinkpadTStore thinkpadT60Store = new ThinkpadT60Store();

    ThinkpadT thinkpadT = null;
    // 购买Thinkpad T43笔记本
    thinkpadT = thinkpadT43Store.buyThinkpadT("T43");
    // 购买Thinkpad T60p笔记本
    thinkpadT = thinkpadT60Store.buyThinkpadT("T60p");
  }

}


    这样就将不同型号T系列笔记本的生产进行了更细的划分,降低了简单工厂中工厂类的耦合程度,抽取出来的各种Store只用关心一种型号笔记本的生产,如T43或T60。

    工厂模式的抽象结构图可以表示如下:


    (上图摘自Head First Patterns)

    抽象工厂模式

    什么时候需要使用抽象工厂模式呢?抽象工厂模式用户生产线更复杂的情况下,例如现在除了T系列的Thinkpad笔记本,我们还需要生产R系列和X系列的产品,这时就需要更多的工厂来负责不同系列Thinkpad的生产。


    (上图摘自吕震宇的博客)    

 

Abstract Factory,把英文直接翻译过来的话就是“抽象工厂”,既然是工厂,那就肯定是生产产品的地方。不过,它不是生产同一类的产品,而是生产同一系列的产品。举个例子,广州本田现在生产3种汽车,Odyssey、Accord、Fit,而广本的工厂里面并不是拥有3条不同的生产线以生产不同的汽车。这就非常相似于我们正在讨论的抽象工厂模式,广本在生产不同的汽车时,需要在各个生产环节进行修改,换机器自然是不合适的,因为这3种汽车每天都要生产,分时段而已。如果某一个环节的更换工作出了问题都会有大麻烦,比如Fit的车顶肯定装不到Odyssey上。我们在软件设计的时候也是这样,如果需要某一系列配套的类来进行工作,当这个系列中有一个类用错了,后果都是不好的。再回到广本的例子上,当广本准备生产另外一种汽车时,只需要拥有相应的配套模具(还有其他的一些配件和一些数控设备的控制程序)就可以了,没有必要搞一大堆的生产线。

再来一个生活中的例子,西服+西裤+皮鞋+白衬衫+领带+头发梳得顺顺的,出入高级会所或者重要场合的时候,男人一般都这样穿;休闲装+运动鞋+随意的发型,生活中就这样穿,舒服;睡衣+拖鞋+鸡窝头,早上就这样。每一种都是合适的造型,如果你搞成如下这样的造型就不合适了,西服+西裤+回力鞋+超级大背包+鸡窝头,广州火车站很多同志都是这样打扮的。

抽象工厂模式是一种创建型的模式。上面的比喻说明了抽象工厂就是生产同一个系列产品的东西,因为这一系列的产品是关联的,如果混用就可能出问题,所以就统一的在抽象工厂中进行创建。当要增加一个新的产品系列时,就多写一个工厂子类并添加相应的产品子类就可以了。

我们来看一个类图。 

 


   图中,我们可以看到,客户需要得到某系列的产品的时候,直接用相应的工厂子类来创建产品就可以了。比如,当需要生产Fit时,就用FitFactory,等到换班之后,要生产Odyssey了,直接使用OdysseyFactory替换FitFactory就行了,至于怎么替换就随便了,GoF也给了我们一些建议,我将在后面总结创建型模式的时候讲。

把上面的类图转换成代码,应该是这个样子。 

关于车门的类:

    public abstract class AbstractDoor
    {
    }

    public class FitDoor : AbstractDoor
    {
    }

    public class OdysseyDoor : AbstractDoor
    {
    }


关于底盘的类:

    public abstract class AbstractChassis
    {
    }

    public class FitChassis : AbstractChassis
    {
    }

    public class OdysseyChassis : AbstractChassis
    {
    }


关于工厂的类:

    public abstract class HondaFactory 
    { 
        public abstract AbstractDoor CreateDoor(); 
        public abstract AbstractChassis CreateChassis(); 
    } 
 
    public class FitFactory 
    { 
        public AbstractDoor CreateDoor() 
        { 
            return new FitDoor(); 
        } 
        public AbstractChassis CreateChassis() 
        { 
            return new FitChassis(); 
        } 
    } 
 
    public class OdysseyFactory 
    { 
        public AbstractDoor CreateDoor() 
        { 
            return new OdysseyDoor(); 
        } 
        public AbstractChassis CreateChassis() 
        { 
            return new OdysseyChassis(); 
        } 
    }

 
客户的调用:

    public class Client
    {
        private AbstractDoor _door;
        private AbstractChassis _chassis;
        private HondaFactory _factory;

        public void GetACar(string seriesName)
        {
            this.PrepareFactory(seriesName);
            this._door = this._factory.CreateDoor();
            this._chassis = this._factory.CreateChassis();

            // TODO: Make a car!
        }

        private void PrepareFactory(string seriesName)
        {
            switch(seriesName)
            {
                case "Fit":
                    this._factory = new FitFactory();
                    break;
                case "Odyssey":
                    this._factory = new OdysseyFactory();
                    break;
            }
        }
    }




   抽象工厂的优点很明显了,就是在需要用到一系列相关类的地方,它可以使我们不出错的创建出一系列的类实例,而我们在需要添加新的产品系列的时候,完全不需要考虑其他系列的问题,仅需要将相关的抽象类(工厂已经产品)具体化就可以了。缺点也在这个地方,当工厂需要生产多一种产品(不是系列)的时候,改动将波及所有类,比如,广本打算在每一辆汽车上装一个翅膀,那就需要在工厂中添加一个冲压机(以及各种车型的翅膀模具),还要在焊接科里添加这么一道工序,涂装科以及总装科里面也一样要进行相应的调整。

 

 

工厂子类不一定需要实现父类的所有方法,但要使子类有用的话,我们必须使它的所有方法宣布具体化。这里,就引出几种做法:1、工厂父类可以就是一个接口,以确保其子类一定是具体的;2、我们可以继承抽象的父类,但不完全具体化,这样可以继续细分工厂子类;3、抽象的父类中含有具体的方法,这些方法也可以不加virtual修饰符。最后的这种方法可能是比较灵活一点的。

抽象工厂主要是用在需要一系列相关联的类协同工作的地方,而且这些系列的数量可能会变多,每一个系列完成的工作都不一样,但是调用接口却是一样的。另外,抽象工厂不适合这样一种情况,即每个系列内部的元素数量不能够确定,也就是说,当初设计的时候,系列中有3个配件,后面又涨成5个,之后又涨到7个,这样的话,要改动的地方将多到让人受不了。 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值