码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式——工厂模式

时间:2014-08-17 22:34:23      阅读:415      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   java   使用   os   strong   

工厂模式有两种类型:工厂方法模式和抽象工厂模式

工厂方法模式定义:定义了一个创建对象的接口(这里的接口并不是单单是指java中的interface),但由子类决定实例化的类是哪一个。工厂方法让类把实例化推迟到子类中。
抽象工厂模式定义:提供一个接口(这里的接口并不是单单是指java中的interface),用于创建相关或依赖对象的家族,而不需要明确指定具体的类。

    不管工厂模式的形式是哪一种,我们要清楚的知道工厂模式的作用,工厂模式是用来封装对象的创建的!也就是说工厂模式用来管理创建对象的,其他的一概和工厂模式无关。
    通过封装对象的创建,就可以达到松耦合的目的,因为滥用new关键字会将多个对象绑定起来,从而耦合在一起,而工厂模式就是要将这些耦合解开,然后以最小的耦合来达到相同的目的。
    比如说:现在要在多个村庄之间组建电网,第一种方案就是“图方便原则”,我们忽略掉村与村之间的界限,只要两个住户之间相隔近,不管他俩是不是一个村,我们都将这两家住户连在同一根电线上,当扩展到成百上千的住户的时候,我们可以想象,这时的电路网会错综复杂,难以管理,当需要更改电网的时候,也是牵一发而动全身。第二个方案是将住户以村为单位,或者更小的,我们以生产队为单位,一个生产队里面的住户采取“图方便原则”,而生产队之间用一根电线连接起来,这样生产队内部的调整不会影响到其他的生产队,也便于管理,这样就以最小的耦合来达到了相同的目的。实际上这里的每一个电线连接处我们都可以将其视为一个new关键字。
 
当然上面的例子只是宽泛的类比了一下工厂模式,例子不一定准确,下面通过一个真正的实例来介绍工厂模式中的工厂方法模式
  • 需求说明
    假设现在有一家面食店,在全国都有连锁店,我们要开发一个系统,让计算机来控制机器帮我们做面食。面点的做法在步骤上基本上都差不多:准备材料→烧水下面(同时也加入了调料,我们的调料都是实现和面拼好的)→装盘。但是全国各地的面食的差别主要在于食材的选择,调料的搭配方面。我们的店要入乡随俗,生产符合当地口味的面食,所以我们的系统要依据地方而有不同的实现。我们不能针对每一个地方都单独的开发一套系统,这样会导致成本过高,我们需要做的就是将公共的地方提出来,然后根据不同地域来实现那些没有公共部分的代码。
  • 系统设计
    java只给我们提供了一个new关键字来创建对象,设计模式不是要求我们不使用这个关键字(不允许使用的话,连对象都创建不了了),而是要求我们不要到处滥用这个关键字,最好是将这个关键字的使用限定在某些区域,这样就便于更改和管理。
    需要使用new的地方,就是对象之间关联的地方,也就是耦合发生的地方,虽然完全消除对象之间的关联是一件不可能的事情,但是我们可以在保证需求的前提下,尽量的减少耦合,或者将耦合全部集中到一个易于管理的地方。
    对于 本例子来说,对象之间的关联在于:①具体的店铺和抽象店铺的关联;②具体面食与抽象面食之间的关联。我们可以将抽象店铺与具体店铺之间用一个new关键字来关联,同时将同一类店铺中所有的面食种类全部封装在店铺内部,这样每个店铺就可以管理自己的面食,店铺与店铺之间不相关联。
bubuko.com,布布扣
 
  • 系统实现
 1 面食抽象类:
 2 /**
 3  * 声明为抽象方法,不能直接new,实例化交给工厂来做
 4  * @author Apache_xiaochao
 5  *
 6  */
 7 public abstract class Noodle {
 8 
 9  private String name; // 名称
10  private String dough; // 面团
11  private List<String> spices; // 调料
12 
13  /**
14   * 准备食材
15   */
16  public void prepare() {
17   System.out.println(
18     "正在准备食材,面食名称:" + this.getName() +
19     " 面团名称:" + this.getDough() +
20     " 调料:" + spices.toString());
21  }
22 
23  /**
24   * 烧水
25   */
26  public void boilWater() {
27       System.out.println("正在烧水...");
28  }
29 
30  /**
31   * 煮面
32   */
33  public void cook() {
34       System.out.println("正在煮面...");
35  }
36 
37  /**
38   * 装盘
39   */
40  public void sabot() {
41       System.out.println("正在装盘...");
42  }    
43     //余下的get和set方法,省略...
44 }
 1 面食店抽象类:
 2 /** 
 3  * 面食店抽象类,所有的面食店都需要继承这个抽象类
 4  * @author Apache_xiaochao
 5  *
 6  */
 7 public abstract class NoodleStore {
 8  
 9 /**
10   * 根据用户需求制作相应的面食
11   * @param type
12   * @return
13   */
14  public Noodle orderNoodle(String type){
15   Noodle noodle = null;
16   if(type != null){
17    noodle = createNoodle(type);
18    noodle.prepare();
19    noodle.boilWater();
20    noodle.cook();
21    noodle.sabot();
22   }
23   return noodle;
24  }
25  
26  /**
27   * 工厂方法 ,将new全部集中到这个方法里面去,然后将new延迟到子类中实现
28   * @param type
29   * @return
30   */
31  protected abstract Noodle createNoodle(String type);       //这里是核心,工厂方法就在这
32 //上面定义了一个抽象的工厂方法,也可以不是抽象的,我们可以在这里定义一个默认的工厂。
33 //这里讲所有的new全部集中到工厂方法中进行管理,每个子类都可以在该方法中管理自己的对象
34 //这里采用的是“参数化工厂方法”,可以根据传递的参数而创建不同的对象,然而工厂常常只产生一种对象,因此不需要参数化
35 
36 }
 1 具体的面食店,以山西面食馆为例:
 2 /**
 3  * 山西面食馆
 4  *
 5  * @author Apache_xiaochao
 6  *
 7  */
 8 public class ShanXiNoodleStore extends NoodleStore {
 9 
10  @Override
11  protected Noodle createNoodle(String type) {
12   Noodle noodle = null;
13   if (type != null) {
14    if ("saozi".equalsIgnoreCase(type)) {
15     noodle = new SXSaoziNoodle();
16    } else if ("liujian".equalsIgnoreCase(type)) {
17     noodle = new SXLiujianNoodle();
18    }
19   }
20   return noodle;
21  }
22 
23 }
24     在这个具体的面食店里面,我们使用了很多的new,这些new可以轻松被管理,如果以后这家店希望添加新的面食,或者减少不受欢迎的面食,改起来就方便很多。
整个架构中代码执行过程说明:
  • 我们先在某个地方开一家山西面食馆:NoodleStore noodleStore = new ShanXiNoodleStore();  //店铺开起来了
  • 假设现在有一位顾客走进我们新开的面食馆,点了一份臊子面:noodleStore.orderNoodle("saozi");  //来生意啦
  • 点完餐之后,系统开始运行,步骤如下:

bubuko.com,布布扣

因为是在山西面食馆里面点餐,所以是山西面食馆里面的系统在为我们服务,当指定面食类型之后,系统就会为我们准备后相应的食材,然后开始制作面食(这些基本上都是大同小异,如果有不同的地方,可以覆盖父类中的相关方法)
 
对于工厂方法的总结:
    工厂模式都是用来封装对象的创建的。工厂方法模式属于工厂模式,当然也是为封装对象创建而服务的,由上面的例子我们可以看,所有对象的创建都被封装到工厂方法之中,而且这个方法的实现,并没有在NoodleStore这个类中,而是在NoodleStore的子类中,因为子类更加清楚要做什么,这样就在一定程度上达到了松耦合的目的,并且让代码更加清晰、灵活、易于扩展。
再次给出工厂方法模式的定义:定义一个创建对象的接口(这里的接口就是指工厂方法),但由子类决定要实例化的类是哪一个(工厂方法的实现在子类中)。工厂方法让类把实例化推迟到子类。

接下来我们仍然使用这个例子来讲解抽象工厂模式
  • 需求说明
    为了保质保量,我们需要控制所有连锁店的食材来源的质量,所以我们决定每个省都指定一个专门的工厂用于提供食材。
  • 系统设计
    这一次我们选用抽象工厂,既然也属于工厂模式,那么它的作用还是用来封装对象的创建。(下图为相应UML图,不过已经没有什么可看性了,太复杂)
bubuko.com,布布扣
  • 系统实现
 1 抽象工厂接口:
 2 /** 
 3  * 抽象工厂
 4  * @author Apache_xiaochao
 5  *
 6  */
 7 public interface NoodleIngredientFactory {
 8  
 9  public abstract Dough orderDough();     //提供面团
10  public abstract Shallot orderShallot();     //提供小葱
11  public abstract Chili orderChili();     //提供辣椒
12  public abstract Egg orderEgg();     //提供鸡蛋
13  
14 }
15     抽象工厂中定义了各种各样食材的供应方法,这些都返回了相应的食材对象,肯定需要用到很多new关键字,这里我们用抽象工厂将它们封装起来。
 1 具体工厂的实现(以东北食材供应工厂为例):
 2 /** 
 3  * 东北原料工厂,这个工厂为东北全境的东北面食馆提供食材
 4  * @author Apache_xiaochao
 5  *
 6  */
 7 public class DongBeiIngredientFactory implements NoodleIngredientFactory {
 8 
 9  @Override
10  public Dough orderDough() {
11   Dough dough = new Dough();
12   dough.setName("黑龙江优质小麦");
13   return dough;
14  }
15 
16  @Override
17  public Shallot orderShallot() {
18   Shallot shallot = new Shallot();
19   shallot.setName("山东大葱");
20   return shallot;
21  }
22 
23  @Override
24  public Chili orderChili() {
25   Chili chili = new Chili();
26   chili.setName("西北红辣椒");
27   return chili;
28  }
29 
30  @Override
31  public Egg orderEgg() {
32   Egg egg = new Egg();
33   egg.setName("农家土鸡蛋");
34   return egg;
35  }
36 
37 }
 1 具体面食馆的实现(以东北面食馆为例):
 2 /**
 3  * 东北面食馆
 4  *
 5  * @author Apache_xiaochao
 6  *
 7  */
 8 public class DongBeiNoodleStore extends NoodleStore {
 9  
10  private NoodleIngredientFactory nif;
11  
12  //在构造方法中指定由哪个食材工厂来提供食材
13  public DongBeiNoodleStore() {
14       this.nif = new DongBeiIngredientFactory();
15  }
16 
17  @Override
18  protected Noodle createNoodle(String type) {
19   Noodle noodle = null;
20   if (type != null) {
21    if ("yangchun".endsWith(type)) {
22     noodle = new DBYangchunNoodle(nif);
23    } else if ("dawan".equalsIgnoreCase(type)) {
24     noodle = new DBDawanNoodle(nif);
25    }
26   }
27   return noodle;
28  }
29 
30 }
对于抽象工厂模式的总结:抽象工厂也是工厂模式的一种,本质上还是封装对象的创建。在本例子中我们可以看到,抽象工厂将食材的创建全部封装到抽象工厂中,不同的地区可以根据当地的特点来创建属于本地区的食材供应市场,而整个程序不需要因为地域之间不同而发生改变,每个区域只要创建一个食材供应市场,然后在自己店铺的系统中指定它既可。

工厂方法与抽象工厂之间的区别:
  • 利用工厂方法创建对象,需要扩展一个类,并覆盖对应的工厂方法
  • 提供一个封装对象创建的抽象类型,这个类型的子类或者是实现类定义了对象创建的方法,然后实例化这个工厂,并将其传到需要需要使用它的地方
  • 工厂方法封装的是某一类对象的创建,每次只提供一个对象
  • 抽象工厂封装的是一群相关的产品集合,可以同时提供多个对象
  • 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
  • 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中

如有错误,恳请读者指正!

设计模式——工厂模式,布布扣,bubuko.com

设计模式——工厂模式

标签:style   blog   http   color   java   使用   os   strong   

原文地址:http://www.cnblogs.com/xiaochao-cs-whu/p/3918337.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!