Java设计模式之-----工厂模式(简单工厂,抽象工厂)

一、工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

工厂模式在《Java与模式》中分为三类:
1)简单工厂模式(Simple Factory):不利于产生系列产品;

2)工厂方法模式(Factory Method):又称为多形性工厂;

3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
             这三种模式从上到下逐步抽象,并且更具一般性。
             GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

二、简单工厂模式

简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。

在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。
        先来看看它的组成:

1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。

2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。

3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

 
主要有一个静态方法,用来接受参数,并根据参数来决定返回实现同一接口的不同类的实例。我们来看一个具体的例子:
假设一家工厂,几生产洗衣机,有生产冰箱,还有空调等等..
我们先为所有产品定义一个共同的产品接口
 public interface Product{} 

接着我们让这个工厂的所有产品都必须实现此接口

 public class Washer implements Product{
public Washer(){
System.out.println("洗衣机被制造了");
}
} public class Icebox implements Product{
public Icebox(){
System.out.println("冰箱被制造了");
}
} public class AirCondition implements Product{
public Icebox(){
System.out.println("空调被制造了");
}
}
接下来我们来写一个工厂类,有它来负责生产以上的产品
 public class SimpleFactory { 

     public static Product factory(String productName) throws Exception{
if(productName.equals("Washer")){
return new Washer();
}else if(productName.equals("Icebox")){
return new Icebox();
}else if(productName.equals("AirCondition")){
return new AirCondition();
}else{
throw new Exception("没有该产品");
}
}
}
好了,有了这个工厂类,我们就可以开始下定单了,SimpleFactory将根据不同的定单类决定生产什么产品。
 public static void main(String[] args) {
try {
SimpleFactory.factory("Washer");
SimpleFactory.factory("Icebox");
SimpleFactory.factory("AirCondition");
} catch (Exception e) {
e.printStackTrace();
}
}
 
由上面的代码可以看出,简单工厂的核心就是一个SimpleFactory类,他拥有必要的逻辑判断能力和所有产品的创建权利,我们只需要向把定单给他,就能得到我们想要的产品。这使用起来似乎非常方便。
但,实际上,这个SimpleFactory有很多的局限。首先,我们每次想要增加一种新产品的时候,都必须修改SimpleFactory的原代码。其次,当我们拥有很多很多产品的时候,而且产品之间又存在复杂的层次关系的时候,这个类必须拥有复杂的逻辑判断能力,其代码量也将不断地激增,这对以后的维护简直就是恐怖两个字...
还有就是,整个系统都严重依赖SimpleFactory类,只要SimpleFactory类一出问题,系统就进入不能工作的状态,这也是最为致命的一点....
以上的不足将在工厂模式的另外两种状态中得到解决。
 
三、工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。
  来看下它的组成:

1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

 
上面的代码告诉我们,简单工厂并不简单,它是整个模式的核心,一旦他出了问题,整个模式都将受影响而不能工作,为了降低风险和为日后的维护、扩展做准备,我们需要对它进行重构,引入工厂方法。
工厂方法为工厂类定义了接口,用多态来削弱了工厂类的职能,以下是工厂接口的定义:
 public interface Factory{
public Product create();
}

我们再来定义一个产品接口

 public interface Product{} 
一下是实现了产品接口的产品类
 public class Washer implements Product{
public Washer(){
System.out.println("洗衣机被制造了");
}
} public class Icebox implements Product{
public Icebox(){
System.out.println("冰箱被制造了");
}
} public class AirCondition implements Product{
public Icebox(){
System.out.println("空调被制造了");
}
}
 

接下来,就是工厂方法的核心部分,也就是具体创建产品对象的具体工厂类,

 //创建洗衣机的工厂
public class CreateWasher implements Factory{
public Product create(){
return new Washer();
}
} //创建冰箱的工厂
public class CreateIcebox implements Factory{
public Product create(){
return new Icebox();
}
} //创建空调的工厂
public class CreateAirCondition implements Factory{
public Product create(){
return new AirCondition();
}
}

从上面创建产品对象的代码可以看出,工厂方法和简单工厂的主要区别是,简单工厂是把创建产品的职能都放在一个类里面,而工厂方法则把不同的产品放在实现了工厂接口的不同工厂类里面,这样就算其中一个工厂类出了问题,其他工厂类也能正常工作,互相不受影响,以后增加新产品,也只需要新增一个实现工厂接口工厂类,就能达到,不用修改已有的代码。但工厂方法也有他局限的地方,那就是当面对的产品有复杂的等级结构的时候,例如,工厂除了生产家电外产品,还生产手机产品,这样一来家电是手机就是两大产品家族了,这两大家族下面包含了数量众多的产品,每个产品又有多个型号,这样就形成了一个复杂的产品树了。如果用工厂方法来设计这个产品家族系统,就必须为每个型号的产品创建一个对应的工厂类,当有数百种甚至上千种产品的时候,也必须要有对应的上百成千个工厂类,这就出现了传说的类爆炸,对于以后的维护来说,简直就是一场灾难.....

 
 
四、简单工厂和工厂方法模式的比较

工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。 
反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。

 
五. 抽象工厂(Factory Method)
抽象工厂:意的意图在于创建一系列互相关联或互相依赖的对象。<<Java设计模式>>
我自己觉得抽象工厂是在工厂方法的基础上引进了分类管理的概念....
工厂方法用来创建一个产品,它没有分类的概念,而抽象工厂则用于创建一系列产品,所以产品分类成了抽象工厂的重点,
我们继续用上面的例子来说明:
工厂生产的所有产品都用都用大写字母来标明它们的型号,比如冰箱,就有“冰箱-A",“冰箱-B",同样,其他的产品也都是遵守这个编号规则,于是就有了一下产品家族树
 
冰箱:
  1. 冰箱-A
  2. 冰箱-B

洗衣机:

  1. 洗衣机-A
  2. 洗衣机-B

我们可以为冰箱和洗衣机分别定义两个产品接口,以对他们进行分类,

 
 //洗衣机接口
public interface Washer{
} //冰箱接口
public interface Icebox{
}

接着,我们分别创建这两个接口的具体产品

 //洗衣机-A
public class WasherA implements Washer{
public WasherA(){
System.out.println("洗衣机-A被制造了");
}
} //洗衣机-B
public class WasherB implements Washer{
public WasherB(){
System.out.println("洗衣机-B被制造了");
}
} //冰箱-A
public class IceboxA implements Icebox{
public IceboxA(){
System.out.println("冰箱-A被制造了");
}
} //冰箱-B
public class IceboxB implements Icebox{
public IceboxB(){
System.out.println("冰箱-B被制造了");
}
}

到此,产品部分我们准备好了,接下来我们来处理工厂部分,我们先来定义工厂行为接口

 public interface Factory{
public Washer createWasher();
public Icebox createIcebox();
}

接下来我创造具体的工厂类,我们根据上面产品的接口,把型号A的产品分为一类,由一个工厂来管理,把型号为B的产品有另一个工厂管理,根据这个分类,我们可以实现如下的两个具体工厂类

 //创建型号为A的产品工厂
public class FactoryA implements Factory{
//创建洗衣机-A
public Washer createWasher(){
return new WasherA();
} //创建冰箱-A
public Icebox createIcebox(){
return new IceboxA();
}
} //创建型号为B的产品工厂
public class FactoryB implements Factory{
//创建洗衣机-B
public Washer createWasher(){
return new WasherB();
} //创建冰箱-B
public Icebox createIcebox(){
return new IceboxB();
}
}

这样,我们的抽象工厂就完成了。有上面可以看出,在运用上我觉得工厂方法和抽象工厂,都有自己的应用场景,并没有什么优劣之分,但在应用抽象工厂之前,要先对创建的对象进行系统的分类,这点很重要,好的产品分类规则能为具体工厂类的选择调用和以后的扩展提供清晰的思路.

 
 
 
 
 
 
上一篇:Jquery datepicker 时间插件使用 js 时间相加,相减


下一篇:jQuery图片剪裁插件Cropper.js的使用