JAVA设计模式之工厂模式

  在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下,new操作符直接生成对象会带来一些问题。举例来说,许多类型对象的创造需要一系列的步骤:你可能需要计算或取得对象的初始设置;选择生成哪个子对象实例;或在生成你需要的对象之前必须先生成一些辅助功能的对象。在这些情况,新对象的建立就是一个 "过程",不仅是一个操作,像一部大机器中的一个齿轮传动。 

模式的问题:你如何能轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程呢?

解决方案:建立一个工厂来创建对象

实现:

一、引言
    1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
    2)简单工厂模式:后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
    3)工厂方法模式时代:为了满足客户,宝马车系列越来越多,如320i,523i,30li等系列一个工厂无法创建所有的宝马系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。

   4)抽象工厂模式时代:随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。

   最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车。

   这就是工厂模式。

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

1)简单工厂模式(Simple Factory) 
2)工厂方法模式(Factory Method) 
3)抽象工厂模式(Abstract Factory) 

这三种模式从上到下逐步抽象,并且更具一般性。 

  GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。

  将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。 

三、区别

工厂方法模式:

一个抽象产品类,可以派生出多个具体产品类。

一个抽象工厂类,可以派生出多个具体工厂类。  

每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:

多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。

一个抽象工厂类,可以派生出多个具体工厂类。

每个具体工厂类可以创建多个具体产品类的实例。
区别:

工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。

工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

两者皆可。

 四、简单工厂模式

建立一个工厂(一个函数或一个类方法)来制造新的对象。

分布说明引子:从无到有。客户自己创建宝马车,然后拿来用。

public class BMW320 {  public BMW320(){  System.out.println("制造-->BMW320");  }  
}  public class BMW523 {  public BMW523(){  System.out.println("制造-->BMW523");  }  
}  public class Customer {  public static void main(String[] args) {  BMW320 bmw320 = new BMW320();  BMW523 bmw523 = new BMW523();  }  
} 

客户需要知道怎么去创建一款车,客户和车就紧密耦合在一起了。为了降低耦合,就出现了工厂类,把创建宝马的操作细节都放到了工厂里面去,客户直接使用工厂的创建工厂方法,传入想要的宝马车型号就行了,而不必去知道创建的细节。这就是工业革命了:简单工厂模式

即我们建立一个工厂类方法来制造新的对象。如图:

产品类:

abstract class BMW {  public BMW(){  }  
}  public class BMW320 extends BMW {  public BMW320() {  System.out.println("制造-->BMW320");  }  
}  
public class BMW523 extends BMW{  public BMW523(){  System.out.println("制造-->BMW523");  }  
}  

工厂类:

public class Factory {  public BMW createBMW(int type) {  switch (type) {  case 320:  return new BMW320();  case 523:  return new BMW523();  default:  break;  }  return null;  }  
}  

客户类:

public class Customer {  public static void main(String[] args) {  Factory factory = new Factory();  BMW bmw320 = factory.createBMW(320);  BMW bmw523 = factory.createBMW(523);  }  
}  

简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。 
  先来看看它的组成: 
    1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
    2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。         
         3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。 

  下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。当客户不再满足现有的车型号的时候,想要一种速度快的新型车,只要这种车符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的;但是工厂部分好像不太理想,因为每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑(createBMW(int type)方法需要新增case),这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。

  我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。

  于是工厂方法模式作为救世主出现了。工厂类定义成了接口,而每新增的车种类型,就增加该车种类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码。

五、工厂方法模式 
  工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。 

工厂方法模式组成: 

  1)抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 
  2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。 
  3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 
  4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 

  工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有 的代码。可以看出工厂角色的结构也是符合开闭原则的! 

代码如下:

产品类:

abstract class BMW {  public BMW(){  }  
}  
public class BMW320 extends BMW {  public BMW320() {  System.out.println("制造-->BMW320");  }  
}  
public class BMW523 extends BMW{  public BMW523(){  System.out.println("制造-->BMW523");  }  
}  

创建工厂类:

interface FactoryBMW {  BMW createBMW();  
}  public class FactoryBMW320 implements FactoryBMW{  @Override  public BMW320 createBMW() {  return new BMW320();  }  }  
public class FactoryBMW523 implements FactoryBMW {  @Override  public BMW523 createBMW() {  return new BMW523();  }  
}  

客户类:

public class Customer {  public static void main(String[] args) {  FactoryBMW320 factoryBMW320 = new FactoryBMW320();  BMW320 bmw320 = factoryBMW320.createBMW();  FactoryBMW523 factoryBMW523 = new FactoryBMW523();  BMW523 bmw523 = factoryBMW523.createBMW();  }  
}  

 工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口,但使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。

例子背景:

随着客户的要求越来越高,宝马车需要不同配置的空调和发动机等配件。于是这个工厂开始生产空调和发动机,用来组装汽车。这时候工厂有两个系列的产品:空调和发动机。宝马320系列配置A型号空调和A型号发动机,宝马230系列配置B型号空调和B型号发动机。

概念:

   抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。

针对百度百科上对于抽象工厂模式的简介,结合本例如下:

当每个抽象产品都有多于一个的具体子类的时候(空调有型号A和B两种,发动机也有型号A和B两种),工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品(产品空调有两个具体产品空调A和空调B)。抽象工厂模式提供两个具体工厂角色(宝马320系列工厂和宝马230系列工厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

抽象工厂模式代码

产品类: 

//发动机以及型号    
public interface Engine {    }    
public class EngineA extends Engine{    public EngineA(){    System.out.println("制造-->EngineA");    }    
}    
public class EngineBextends Engine{    public EngineB(){    System.out.println("制造-->EngineB");    }    
}    //空调以及型号    
public interface Aircondition {    }    
public class AirconditionA extends Aircondition{    public AirconditionA(){    System.out.println("制造-->AirconditionA");    }    
}    
public class AirconditionB extends Aircondition{    public AirconditionB(){    System.out.println("制造-->AirconditionB");    }    
}   

创建工厂类:

//创建工厂的接口    
public interface AbstractFactory {    //制造发动机  public Engine createEngine();  //制造空调   public Aircondition createAircondition();   
}    //为宝马320系列生产配件    
public class FactoryBMW320 implements AbstractFactory{    @Override    public Engine createEngine() {      return new EngineA();    }    @Override    public Aircondition createAircondition() {    return new AirconditionA();    }    
}    
//宝马523系列  
public class FactoryBMW523 implements AbstractFactory {    @Override    public Engine createEngine() {      return new EngineB();    }    @Override    public Aircondition createAircondition() {    return new AirconditionB();    }    }   

客户:

public class Customer {    public static void main(String[] args){    //生产宝马320系列配件  FactoryBMW320 factoryBMW320 = new FactoryBMW320();    factoryBMW320.createEngine();  factoryBMW320.createAircondition();  //生产宝马523系列配件    FactoryBMW523 factoryBMW523 = new FactoryBMW523();    factoryBMW320.createEngine();  factoryBMW320.createAircondition();  }    
}  

关于抽象工厂模式与工厂方法模式的区别,这里就不说了,感觉多看几遍例子就能理解,还有很多提到的产品族、等级结构等概念,说了反而更难理解。

抽象工厂模式的起源

下面引用一段抽象工厂模式的起源:
抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。
在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。

可以发现在上面的产品类图中,有两个产品的等级结构,分别是Button等级结构和Text等级结构。同时有两个产品族,也就是UNIX产品族和Windows产品族。UNIX产品族由UNIX Button和UNIX Text产品构成;而Windows产品族由Windows Button和Windows Text产品构成。

系统对产品对象的创建需求由一个工程的等级结构满足,其中有两个具体工程角色,即UnixFactory和WindowsFactory。UnixFactory对象负责创建Unix产品族中的产品,而WindowsFactory对象负责创建Windows产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图:

显然,一个系统只能够在某一个操作系统的视窗环境下运行,而不能同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。

在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了。

总结:

  无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

本文转自:http://blog.csdn.net/jason0539/article/details/23020989

转载于:https://www.cnblogs.com/dreammyle/p/5405092.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/490899.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

纳米片晶体管是摩尔定律的下一步,也许是最后一步!

来源:云头条作者:Peide Ye是普渡大学的Richard J.和Mary Jo Schwartz电气与计算机工程教授,Thomas Ernst是法国格勒诺布尔CEA-Leti的科学主任,Mukesh V. Khare是IBM研究中心的半导体和AI硬件副总裁。纳米片器件计划最快在2021年用…

IAR STM32工程报错Error[Pe020]: identifier “GPIO_Pin_0”is undefined D:\STM32F103_Demo\App\main.c

IAR STM32工程报错: Error[Pe020]: identifier "GPIO_Pin_0" is undefined D:\STM32F103_Demo\App\main.c 解决方法: 右键下图工程名选择Options 在预处理里面加上下面这行

脑机接口技术的现状与未来!

来源:芯智讯一、前言通过在脑后插入一根线缆,我们就能够畅游计算机世界;只需一个意念我们就能改变“现实”;学习知识不再需要通过书本、视频等媒介,也不需要在花费大量的时间,只需直接将知识传输到大脑当中…

学籍管理系统系统流程图

转载于:https://www.cnblogs.com/whitelip/p/5406976.html

崛起的超级智能:是否会是下一个“麦克卢汉式”预言?

腾讯科技21世纪以来,前沿科技领域呈爆发式增长:从云计算到区块链、从谷歌大脑到华为EI智能体、从工业大脑到农业大脑、从城市神经网络到智慧社会……各种新技术和新概念层出不穷,如潮水般不断涌现,无论业界学界还是行业产业&#…

HttpClient Get/Post方式调用Http接口

HttpClient Get/Post方式调用Http接口 本节摘要:本节主要分别介绍如何用get方式、post方式向http接口发送数据。 preparation 1. 项目环境如下: myeclipse6.5 、tomcat5.0、system:xp、JDK:开发1.5,编译1.4 为了方便,在原来的web项目UpDown中新建了一个h…

python对Excel的操作 xlrd、xlwt包详解

文章更新中............. python中对Excel表格的操作,主要用到两个包,分别是xlrd和xlwt 1.xlrd主要用于读Excel表 2.xlwt则主要用于写Excel python—xlrd 这里我先准备了一些济南天气的一些数据通过python程序先对数据有一个基本的了解: path…

人造细胞能模仿天然细胞感知环境

来源:科技日报据英国帝国理工学院官网近日消息,该校一个研究团队成功开发出一种新型人造细胞,能够模仿天然细胞感知环境中的化学变化并产生反应。如果在未来发展成熟,这项技术可广泛用于生物科技等领域。相关成果已刊登在近期美国…

FileNotFoundError: [Errno 2] No such file or directory: 'test/条形图03.html'

这几天一直在搞百度的一个可视化的工具Echart,感觉确实挺不错的,比matplotlib的可视化好看多了。 今天遇到了两个问题 1、如何导入pyecharts中的get_all_options工具 解决方法: from pyecharts.echarts.option import get_all_options 2、在进…

感觉皮层实质性参与工作记忆的信息保存

来源:脑智卓越创新中心7月17日,《eLife》期刊在线发表了题为《感觉皮层实质性参与工作记忆的信息保存》的研究论文。该研究由中国科学院脑科学与智能技术卓越创新中心(神经科学研究所)、上海脑科学与类脑研究中心、神经科学国家重…

孙正义看科技未来:今后30年要把钱和精力投向哪里

来源:dang归网孙正义,软银集团创办人对于今后30年来讲,我认为现在个很关键的时刻,尤其是在各位的人生当中。而且现在是一整个概念的转变,我们要包容这个概念的转变,我想先给大家看两张照片。这是美国纽约的…

python+OpenCV图像处理(一)读取、复制、显示、保存

前 言 从2017年入坑人工智能领域开始,就被这一领域深深的所吸引,虽然到现在已经踩了不少坑,但总算有了不少的收获,深感不虚此行,借助强大的python让我快速的向着这一领域靠近,现在流行比较广的人工智能应用…

python+OpenCV图像处理(二)图像像素的访问、通道的合并与分离

图像像素的访问、通道的合并与分离 (一)像素访问 在第一篇博客中,向大家介绍了,所谓的图像在计算机看来就是一个矩阵,对于RGB图像矩阵一共有三层,分别代表着RGB通道,矩阵中每一个数的大小代表着…

PNG转EPS格式

由于使用LaTeX需要将png格式转为eps格式,如果电脑装了tex软件,则转换方式很简单: 首先打开需要转换的图片所在文件夹。在地址栏输入cmd: 此时会弹出,命令窗口,然后输入bmeps -c Figure1.png Figure1.eps 即…

工业根基,莫让ICT喧宾夺主

来源:英诺维盛公司新工业革命正在得到广泛的关注,而ICT则获得了更高的曝光率和话语权。ICT是信息、通信和技术三个英文词首字母组合(Information Communications Technology)。显然,ICT是新工业革命必不可少的“新工业…

python+OpenCV图像处理(三)绘制简单的几何图形、显示文字

绘制简单的几何图形、显示文字 (一)绘制直线和矩形 img np.zeros([512, 512, 3]) # line函数用来画直线,第一个参数可以理解为画布矩阵, # 第二个参数pt1是直线的起始位置,第三个参数pt2是直线的终止位置,…

信息转换原理: 信息、知识、智能的一体化理论

来源:人机与认知实验室【数据、信息、知识、智能除了转换外,是否还有变异、弥聚等?能否把这些变化看成是态、势、感、知结构扭曲而产生的必然现象?】摘要 如何把信息转换为解决问题所需要的智能,是信息科学领域的核心研究课题. 本…

MATLAB(一)Matlab“帮助”的使用

前言MATLAB是matrix和laboratory两个词的组合,意为矩阵工厂(矩阵实验室)。是由美国mathworks公司发布的主要面对科学计算、可视化以及交互式程序设计的高科技计算环境。它将数值分析、矩阵计算、科学数据可视化以及非线性动态系统的建模和仿真…

javascript 学习笔记(一)

说明:从今天开始从基础抓起学习javascript-完全依据w3school(http://www.w3school.com.cn/js/js_intro.asp)网站顺序。这里我将我认为不好理解的地方积累下来,希望对像我一样的新手有益。 第一篇 JavaScript:写入 HTML 输出 1. javascript有…

[附下载]英特尔中国研究院携手生态伙伴发布《机器人4.0白皮书》

来源:硬蛋迈向云-边-端融合的机器人4.0时代在2019国际人工智能与机器人创新生态峰会上,英特尔中国研究院院长宋继强博士发表了题为《迈向云-边-端融合的机器人4.0时代》的主题演讲。宋院长分析了机器人行业的现状与发展趋势,提出了基于AI、5G…