结合简单示例和UML图,讲解工厂模式简单原理。

一、引子

话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰)、Bmw(宝马)、Audi(奥迪)),还雇了司机为他开车。不过,爆发户坐车时总是这样:上Benz车后跟司机说“开奔驰车!”,坐上Bmw后他说“开宝马车!”,坐上 Audi后他说“开奥迪车!”。
你一定说:这人有病!直接说开车不就行了?!而当把这个爆发户的行为放到我们程序语言中来,我们发现C语言一直是通过这种方式来坐车的!
幸运的是这种有病的现象在OO语言中可以避免了。下面以Java语言为基础来引入我们本文的主题:工厂模式!

二、简介

工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类:
1. 简单工厂模式(Simple Factory)
2. 工厂方法模式(Factory Method)
3. 抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。还有一种分类法,就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。两者皆可,这本为使用《Java与模式》的分类方法。
在什么样的情况下我们应该记得使用工厂模式呢?大体有两点:
1.在编码时不能预见需要创建哪种类的实例。
2.系统不应依赖于产品类实例如何被创建、组合和表达的细节
工厂模式能给我们的OOD、OOP带来哪些好处呢??

三、简单工厂模式

这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改)。
它由三种角色组成:
工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品。如例子中的Driver类。
抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。
具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现,如例子中的Benz、Bmw类。
来用类图来清晰的表示下的它们之间的关系:


下面就来给那个暴发户治病:在使用了简单工厂模式后,现在暴发户只需要坐在车里对司机说句:“开车”就可以了。来看看怎么用代码实现的:(为方便起见,所有的类放在一个文件中,故有一个类被声明为public)

//抽象产品
abstract class Car{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
//具体产品
class Benz extends Car{  public void drive(){  System.out.println(this.getName()+"----go-----------------------");  }
}  class Bmw extends Car{  public void drive(){  System.out.println(this.getName()+"----go-----------------------");  }
}  //简单工厂
class Driver{  public static Car createCar(String car){  Car c = null;  if("Benz".equalsIgnoreCase(car))  c = new Benz();  else if("Bmw".equalsIgnoreCase(car))  c = new Bmw();  return c;  }
}  //老板
public class BossSimplyFactory {  public static void main(String[] args) throws IOException {  //老板告诉司机我今天坐奔驰  Car car = Driver.createCar("benz");  car.setName("benz");  //司机开着奔驰出发  car.drive();  }
}

如果老板要坐奥迪,同理。

这便是简单工厂模式了。那么它带了了什么好处呢?
首先,符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品(正如暴发户所为)。
下面我们从开闭原则上来分析下简单工厂模式。当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。(即创建一个新的车类,继承抽象产品Car)那么 对于产品部分来说,它是符合开闭原则的——对扩展开放、对修改关闭;但是工厂类不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判 断逻辑,这显自然是违背开闭原则的。

而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了。
正如我前面提到的简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应了。这就应该由工厂方法模式来出场了!!

四、工厂方法模式
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
来用类图来清晰的表示下的它们之间的关系:

话说暴发户生意越做越大,自己的爱车也越来越多。这可苦了那位司机师傅了,什么车它都要记得,维护,都要经过他来使用!于是暴发户同情他说:我给你分配几个人手,你只管管好他们就行了!于是工厂方法模式的管理出现了。代码如下:

//抽象产品
abstract class Car{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
//具体产品
class Benz extends Car{  public void drive(){  System.out.println(this.getName()+"----go-----------------------");  }
}
class Bmw extends Car{  public void drive(){  System.out.println(this.getName()+"----go-----------------------");  }
}  //抽象工厂
abstract class Driver{  public abstract Car createCar(String car) throws Exception;
}
//具体工厂(每个具体工厂负责一个具体产品)
class BenzDriver extends Driver{  public Car createCar(String car) throws Exception {  return new Benz();  }
}
class BmwDriver extends Driver{  public Car createCar(String car) throws Exception {  return new Bmw();  }
}  //老板
public class Boss{  public static void main(String[] args) throws Exception {  Driver d = new BenzDriver();  Car c = d.createCar("benz");   c.setName("benz");  c.drive();  }
}  

使用开闭原则来分析下工厂方法模式。当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并基础抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的!

使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。
当然特殊的情况,就要特殊对待了:对于系统中存在不同的产品树,而且产品树上存在产品族(下一节将解释这个名词)。那么这种情况下就可能可以使用抽象工厂模式了。

五、小结

让我们来看看简单工厂模式、工厂方法模式给我们的启迪:
如果不使用工厂模式来实现我们的例子,也许代码会减少很多——只需要实现已有的车,不使用多态。但是在可维护性上,可扩展性上是非常差的(你可以想象一下添加一辆车后要牵动的类)。因此为了提高扩展性和维护性,多写些代码是值得的。

六、抽象工厂模式

先来认识下什么是产品族: 位于不同产品等级结构中,功能相关联的产品组成的家族。

图中的BmwCar和BenzCar就是两个产品树(产品层次结构);而如图所示的BenzSportsCar和BmwSportsCar就是一个产品族。他们都可以放到跑车家族中,因此功能有所关联。同理BmwBussinessCar和BenzBusinessCar也是一个产品族。
可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。
而且使用抽象工厂模式还要满足一下条件:
1.系统中有多个产品族,而系统一次只可能消费其中一族产品
2.同属于同一个产品族的产品以其使用。
来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

//抽象产品(Bmw和Audi同理)
abstract class BenzCar{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
//具体产品(Bmw和Audi同理)
class BenzSportCar extends BenzCar{  public void drive(){  System.out.println(this.getName()+"----BenzSportCar-----------------------");  }
}
class BenzBusinessCar extends BenzCar{  public void drive(){  System.out.println(this.getName()+"----BenzBusinessCar-----------------------");  }
}  abstract class BmwCar{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
class BmwSportCar extends BmwCar{  public void drive(){  System.out.println(this.getName()+"----BmwSportCar-----------------------");  }
}
class BmwBusinessCar extends BmwCar{  public void drive(){  System.out.println(this.getName()+"----BmwBusinessCar-----------------------");  }
}  abstract class AudiCar{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
class AudiSportCar extends AudiCar{  public void drive(){  System.out.println(this.getName()+"----AudiSportCar-----------------------");  }
}
class AudiBusinessCar extends AudiCar{  public void drive(){  System.out.println(this.getName()+"----AudiBusinessCar-----------------------");  }
}  //抽象工厂
abstract class Driver3{  public abstract BenzCar createBenzCar(String car) throws Exception;  public abstract BmwCar createBmwCar(String car) throws Exception;  public abstract AudiCar createAudiCar(String car) throws Exception;
}
//具体工厂
class SportDriver extends Driver3{  public BenzCar createBenzCar(String car) throws Exception {  return new BenzSportCar();  }  public BmwCar createBmwCar(String car) throws Exception {  return new BmwSportCar();  }  public AudiCar createAudiCar(String car) throws Exception {  return new AudiSportCar();  }
}
class BusinessDriver extends Driver3{  public BenzCar createBenzCar(String car) throws Exception {  return new BenzBusinessCar();  }  public BmwCar createBmwCar(String car) throws Exception {  return new BmwBusinessCar();  }  public AudiCar createAudiCar(String car) throws Exception {  return new AudiBusinessCar();  }
}  //老板
public class BossAbstractFactory {  public static void main(String[] args) throws Exception {  Driver3 d = new BusinessDriver();  AudiCar car = d.createAudiCar("");  car.drive();  }
}  

其中:BenzSportCar和BenzBusinessCar属于产品树;同理BmwSportCar和BmwBusinessCar。而BenzSportCar和BmwSportCar和AudiSportCar属于产品族。

所以抽象工厂模式一般用于具有产品树和产品族的场景下。

抽象工厂模式的缺点:如果需要增加新的产品树,那么就要新增三个产品类,比如VolvoCar,VolvoSportCar,VolvoSportCar,并且要修改三个工厂类。这样大批量的改动是很丑陋的做法。

所以可以用简单工厂配合反射来改进抽象工厂:
UML图略。

abstract class BenzCar{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
class BenzSportCar extends BenzCar{  public void drive(){  System.out.println(this.getName()+"----BenzSportCar-----------------------");  }
}
class BenzBusinessCar extends BenzCar{  public void drive(){  System.out.println(this.getName()+"----BenzBusinessCar-----------------------");  }
}  abstract class BmwCar{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
class BmwSportCar extends BmwCar{  public void drive(){  System.out.println(this.getName()+"----BmwSportCar-----------------------");  }
}
class BmwBusinessCar extends BmwCar{  public void drive(){  System.out.println(this.getName()+"----BmwBusinessCar-----------------------");  }
}  abstract class AudiCar{  private String name;  public abstract void drive();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }
}
class AudiSportCar extends AudiCar{  public void drive(){  System.out.println(this.getName()+"----AudiSportCar-----------------------");  }
}
class AudiBusinessCar extends AudiCar{  public void drive(){  System.out.println(this.getName()+"----AudiBusinessCar-----------------------");  }
}  /** * 简单工厂通过反射改进抽象工厂及其子工厂 * @author Administrator * */
class Driver3{  public static BenzCar createBenzCar(String car) throws Exception {  return (BenzCar) Class.forName(car).newInstance();  }  public static BmwCar createBmwCar(String car) throws Exception {  return (BmwCar) Class.forName(car).newInstance();  }  public static AudiCar createAudiCar(String car) throws Exception {  return (AudiCar) Class.forName(car).newInstance();  }
}
//客户端
public class SimpleAndAbstractFactory {  public static void main(String[] args) throws Exception {  AudiCar car = Driver3.createAudiCar("com.java.pattendesign.factory.AudiSportCar");  car.drive();  }
}  

简单工厂、工厂方法、抽象工厂区别相关推荐

  1. 简单工厂 工厂方法 抽象工厂 如何理解

    文章目录 前言 一.简单工厂 二.工厂方法 三.抽象工厂 总结 前言 简单工厂,工厂方法,抽象工厂,三者有什么区别? 搞清楚他们有什么弊端,以发展的角度去观察,理解会更加深入. 提示:以下是本篇文章正 ...

  2. JAVA工厂模式优缺点_简单工厂模式、工厂模式和抽象工厂模式区别及优缺点

    各位小伙伴好,今天给大家主要介绍一下简单工厂模式.工厂模式和抽象工厂模式的区别及各自的优缺点. (本文实现语言为Python3) [前言] 众所周知今天所讲的内容是 设计模式的一类:对于设计模式这个概 ...

  3. 简单工厂模式、工厂模式和抽象工厂模式区别及优缺点

    各位小伙伴好,今天给大家主要介绍一下简单工厂模式.工厂模式和抽象工厂模式的区别及各自的优缺点. (本文实现语言为Python3) [前言] 众所周知今天所讲的内容是设计模式的一类:对于设计模式这个概念 ...

  4. java 三种工厂模式(简单工厂+工厂方法+抽象工厂)

    一.简单工厂模式 概述   简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的 实例,被创建的实例通常都具有共同的父类.因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因 ...

  5. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂)

    园子里关于23种设计模式的博文已经可以说是成千上万.车载斗量.屯街塞巷.不计其数.数不胜数.摩肩接踵.汗牛充栋.车水马龙.门庭若市.琳琅满目直至让人眼花缭乱了.在这样的大环境下之所以来写设计模式类的博 ...

  6. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录

    1楼留头头大神:http://www.cnblogs.com/toutou/p/4899388.html v阅读目录 v写在前面 v简单工厂模式 v工厂方法模式 v抽象工厂模式 v博客总结 v博客前言 ...

  7. 简单工厂-工厂方法-抽象工厂

    目录 简单工厂 工厂方法 抽象工厂 前言 之前看书认真了解过这三种模式,但因为没有做记录,都给忘完了.现在重新分析网上的博客发现跟书里讲的不太一样,哎-.现在能做的就是把现在的理解给记录一下,若以后有 ...

  8. 设计模式学习笔记——03 简单工厂 工厂方法 抽象工厂

    简单工厂 简单工厂模式也成静态工厂模式,但此模式不符合开闭原则,但仍然很常用 适用范围:工厂类需要创建的对象种类比较少,客户端只需要知道传入工厂类的参数,对于如何创建对象(逻辑)不关心 上段代码: p ...

  9. 简单工厂模式和抽象工厂模式

    简单工厂模式和抽象工厂模式 不BB,直接来需求设计 一个披萨店现在需要生产多种颜色的披萨供顾客使用,我们为了满足生产多种颜色的披萨生产,脑海里面第一想法是使用工厂模式来创建不同的披萨. 先看草图的大致 ...

  10. 工厂设计模式、简单工厂设计模式、抽象工厂设计模式

    一.简单工厂设计模式.工厂设计模式,抽象工厂设计模式总体分析 简单工厂模式 简单工厂模式不是23种里的一种,简而言之,就是有一个专门生产某个产品的类. 比如下图中的鼠标工厂,专业生产鼠标,给参数0,生 ...

最新文章

  1. postman使用介绍
  2. r730xd服务器文档,r730xd配置服务器远程
  3. Matlab实用程序--图形应用-双y轴图形的绘制
  4. 查看某个进程是否还有外部请求进来
  5. python使用近似公式计算e_python如何算自然底数e(方法二)
  6. 引导页 设置只显示一次
  7. 【算法设计与分析】13 分治策略的设计思想
  8. python取的键不存在_Python3基础 dict get 在查询不存在的键时,返回指定的内容
  9. python虚拟人脸生成_Python-OpenCV人脸识别之数据集生成
  10. JPA与EJB3的关系
  11. 免费下载遥感数据的网址
  12. 遥感影像转换成MapGIS识别的msi格式
  13. Windows 10正式版的历史版本
  14. Visual Paradigm简单教程(1):绘制状态机图
  15. oracle10g rac ocssd,求教:安装oracle10g rac 报crs-0223错误问题
  16. 走进音视频的世界——剖析exo播放器架构
  17. RT-1052学习笔记 - GPIO架构分析
  18. centos php-fpm 位置,centos 如何安装 php-fpm
  19. 华为系统怎么使用小米云服务器,从小米的MIUI换成华为EMUI,使用5个月,憋了一肚子的真心话...
  20. Jquery绑定focus事件遇到的问题

热门文章

  1. 肠道重要菌属——嗜胆菌属 (Bilophila)喜欢脂肪、耐胆汁的促炎菌
  2. c语言作业 分解质因数,分解质因数(C语言)
  3. cad直线和圆弧倒角不相切_在cad绘制倒圆角的方法技巧步骤详解
  4. 【Oracle SQL】计算同比与环比(列转行进行偏移)
  5. EXCEL中IF函数的嵌套结构以及AND与OR的用法
  6. Unity 之 发布 WebGl 遇到的问题
  7. 802.11 - 灵活组播服务(Flexible multicast service)
  8. 电脑常用的快捷键大全分享。
  9. 图纸管理软件有哪些,免费图纸管理软件
  10. c# .net Paypal支付Webhooks回调验证