设计模式一 工厂模式Factory

在面向对象编程中, 最通常的方法是一个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)看为工厂方法模式的一种特例,两者归为一类。 

三、差别 

工厂方法模式:

一个抽象产品类。能够派生出多个详细产品类。   

一个抽象工厂类,能够派生出多个详细工厂类。   

每一个详细工厂类仅仅能创建一个详细产品类的实例。

抽象工厂模式:

多个抽象产品类。每一个抽象产品类能够派生出多个详细产品类。   

一个抽象工厂类。能够派生出多个详细工厂类。   

每一个详细工厂类能够创建多个详细产品类的实例。   

差别:

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

工厂方法模式的详细工厂类仅仅能创建一个详细产品类的实例。而抽象工厂模式能够创建多个。

两者皆可。

四、简单工厂模式 

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

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

 

<?php
/**
* 车子系列
*
*/
Class BWM320{
function __construct($pa) { }
}
Class BMW523{
function __construc($pb){ }
} /**
*
* 客户自己创建宝马车
*/
class Customer { function createBMW320(){
return new BWM320();
} function createBMW523(){
return new BMW523();
}
}

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

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

如图:

产品类:

<?php
/**
* 车子系列
*
*/
abstract Class BWM{
function __construct($pa) { }
}
Class BWM320 extends BWM{
function __construct($pa) { }
}
Class BMW523 extends BWM{
function __construc($pb){ }
}

工厂类:

/**
*
* 工厂创建车
*/
class Factory { static function createBMW($type){
switch ($type) {
case 320:
return new BWM320();
case 523:
return new BMW523();
//....
}
}

客户类:

/**
*
* 客户通过工厂获取车
*/
class Customer {
private $BMW;
function getBMW($type){
$this¬-> BMW = Factory::createBMW($type);
}
}

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

      先来看看它的组成: 

         1) 工厂类角色:这是本模式的核心。含有一定的商业逻辑和推断逻辑。

         2) 抽象产品角色:它通常是详细产品继承的父类或者实现的接口。         

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

        

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

        我们举的样例是最简单的情况,而在实际应用中,非常可能产品是一个多层次的树状结构。因为简单工厂模式中仅仅有一个工厂类来相应这些产品。所以这可能会把我们的上帝很累了,也很累了我们这些程序猿:( 

        于是工厂方法模式作为救世主出现了。

工厂类定义成了接口,而每新增的车种类型,就添加该车种类型相应工厂类的实现,这样工厂的设计就能够扩展了,而不必去改动原来的代码。

五、工厂方法模式 

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

工厂方法模式组成: 

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

在java中它由抽象类或者接口来实现。

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

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

       4)详细产品角色:详细工厂角色所创建的对象就是此角色的实例。

在java中由详细的类来实现。

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



代码例如以下:

产品类:

<?php
/**
* 车子系列
*
*/
abstract Class BWM{
function __construct($pa) { }
}
Class BWM320 extends BWM{
function __construct($pa) { }
}
Class BMW523 extends BWM{
function __construc($pb){ }
}

创建工厂类:

/**
* 创建工厂的接口
*
*/
interface FactoryBMW {
function createBMW();
} /**
*
* 创建BWM320车
*/
class FactoryBWM320 implements FactoryBMW {
function createBMW($type){
return new BWM320();
} } /**
*
* 创建BWM523车
*/
class FactoryBWM523 implements FactoryBMW {
function createBMW($type){
return new BMW523();
}
}

客户类:

/**
*
* 客户得到车
*/
class Customer {
private $BMW;
function getBMW($type){
switch ($type) {
case 320:
$BWM320 = new FactoryBWM320();
return $BWM320->createBMW();
case 523:
$BWM523 = new FactoryBWM523();
return $BWM320->createBMW();
//....
} }
}

能够看出工厂方法的增加。使得对象的数量成倍增长。当产品种类许多时,会出现大量的与之相应的工厂对象,这不是我们所希望的。由于假设不能避免这样的情 况。能够考虑使用简单工厂模式与工厂方法模式相结合的方式来降低工厂类:即对于产品树上类似的种类(通常是树的叶子中互为兄弟的)使用简单工厂模式来实 现。

工厂方法小结:

        工厂方法模式仿佛已经非常完美的对对象的创建进行了包装,使得客户程序中只处理抽象产品角色提供的接口。那我们是否一定要在代码中遍布工厂呢?大可不必。或许在以下情况下你能够考虑使用工厂方法模式: 

     1)当客户程序不须要知道要使用对象的创建过程。 

     2)客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个详细的对象。

简单工厂模式与工厂方法模式真正的避免了代码的改动了?没有。在简单工厂模式中,新产品的增加要改动工厂角色中的推断语句;而在工厂方法模式中。要么将判 断逻辑留在抽象工厂角色中。要么在客户程序中将详细工厂角色写死(就象上面的样例一样)。并且产品对象创建条件的改变必定会引起工厂角色的改动。

       面对这样的情况,我们能够使用反射机制:

 class Customer {
private $BMW;
function getBMW($type){
$class = new ReflectionClass('FactoryBWM' .$type );//建立 'FactoryBWM'这个类的反射类
$instance = $class->newInstanceArgs();//相当于实例化'FactoryBWM' .$type类
return $instance->createBMW();
//或者直接
/**
* $instance = new 'FactoryBWM' .$type();
* return $instance->createBMW();
*/
}
}

六、抽象工厂模式 

       随着客户的要求越来越高,宝马车须要配置空调。于是这个工厂開始生产宝马车和配置须要的空调。这时候工厂有二个系列的产品:宝马车和空调.宝马车必须使用相应的空调才干使用.这时候分别使用一个车工厂和一个空调工厂都不能满足我们的需求,我们必须确认车跟空调的相应关系。

因此把车工厂跟空调工厂联系在一起。

因此出现了抽象工厂模式。

     能够说,抽象工厂模式和工厂方法模式的差别就在于须要创建对象的复杂程度上。并且抽象工厂模式是三个里面最为抽象、最具一般性的。

抽象工厂模式的用意为:给client提供一个接口,能够创建多个产品族中的产品对象 。并且使用抽象工厂模式还要满足一下条件:

     1)系统中有多个产品族。而系统一次仅仅可能消费当中一族产品。

     2)同属于同一个产品族的产品以其使用。

抽象工厂模式的各个角色(和工厂方法一样):

     1)抽象工厂角色: 这是工厂方法模式的核心。它与应用程序无关。是详细工厂角色必须实现的接口或者必须继承的父类。

在java中它由抽象类或者接口来实现。 

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

     3)抽象产品角色:它是详细产品继承的父类或者是实现的接口。

4)详细产品角色:详细工厂角色所创建的对象就是此角色的实例。

其结构:

我们的样例:

 



代码:

产品类:

<?php
/**
* 车子系列以及型号
*
*/
abstract class BWM{
} class BWM523 extends BWM {
}
class BWM320 extends BWM { }
/**
* 空调
*
*/
abstract class aircondition{
}
class airconditionBWM320 extends aircondition { }
class airconditionBWM52 extends aircondition { }

创建工厂类:

/**
* 创建工厂的接口
*
*/
interface FactoryBMW {
function createBMW();
function createAirC();
} /**
*
* 创建BWM320车
*/
class FactoryBWM320 implements FactoryBMW {
function createBMW(){
return new BWM320();
}
function createAirC(){ //空调
return new airconditionBWM320();
}
} /**
*
* 创建BWM523车
*/
class FactoryBWM523 implements FactoryBMW {
function createBMW(){
return new BWM523();
}
function createAirC(){
return new airconditionBWM523();
}
}

客户:

/**
*
* 客户得到车
*/
class Customer {
private $BMW;
private $airC;
function getBMW($type){
$class = new ReflectionClass('FactoryBWM' .$type );//建立 Person这个类的反射类
$instance = $class->newInstanceArgs();//相当于实例Person 类别
$this->BMW = $instance->createBMW();
$this->airC = $instance->createAirC();
}
}

设计模式(一)工厂模式Factory(创建类型)的更多相关文章

  1. python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)

    十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...

  2. 设计模式之工厂模式(Factory)

    设计模式的工厂模式一共有三种:简单工厂模式,工厂模式,抽象工厂模式 简单工厂模式原理:只有一个工厂类,通过传参的形式确定所创建的产品对象种类 代码如下: #include <stdio.h> ...

  3. 设计模式~简单工厂模式(Factory)

    简单工厂模式Simple Factory根据提供给它的数据,返回一个类的实例.通常它返回的类都有一个公共的父类(或者接口对象). 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类 ...

  4. Java设计模式02:常用设计模式之工厂模式(创建型模式)

    一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的.  工厂模式在<Java与模式>中分为三类: 1)简单工厂模式(Simple Fact ...

  5. 【设计模式】工厂模式 Factory Pattern

    1)简单工厂(不是模式) 简单工厂只是一种变成习惯,并非23种设计模式之一. 简单工厂提供将实例话那种类型留给运行时判断,而非编译时指定.简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一个类的 ...

  6. JAVA设计模式之工厂模式—Factory Pattern

    1.工厂模式简介 工厂模式用于对象的创建,使得客户从具体的产品对象中被解耦. 2.工厂模式分类 这里以制造coffee的例子开始工厂模式设计之旅. 我们知道coffee只是一种泛举,在点购咖啡时需要指 ...

  7. 设计模式之工厂模式(Factory模式)

    在面向对象系统设计中经常遇到以下两类问题: 1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口.这样我们可以通过声明一个指向基类的 ...

  8. java设计模式之 工厂模式Factory

    好比某种套路,经过不断实践,证明对项目结构非常有利 如果需要获取某种对象,如同获取不同的产品 需要由工厂来提供,工厂模式 可能的类或者对象:工厂类  产品:Cat  Dog  Fish ... //动 ...

  9. 设计模式之工厂模式 Factory实现

    simpleFactory //car接口 public interface Car { void run(); } //两个实现类 public class Audi implements Car{ ...

随机推荐

  1. JOHN W. TUKEY: HIS LIFE AND PROFESSIONAL CONTRIBUTIONS

    DAVID R. BRILLINGER 写的关于John的一片纪念文章 JOHN W. TUKEY: HIS LIFE AND PROFESSIONAL CONTRIBUTIONS  (The Ann ...

  2. html中的rowspan和colspan

    摘自w3school(http://www.w3school.com.cn/tags/att_td_colspan.asp)colspan 属性规定单元格可横跨的列数.<table border ...

  3. maven项目配置Project Facets时further configuration available不出来问题

    如果下边的 further configuration available不出来 把Dynamic web module 去掉勾选,应用与项目,然后再点开项目的properties,再选中Dynami ...

  4. 怎样在Android实现桌面清理内存简单Widget小控件

    怎样在Android实现桌面清理内存简单Widget小控件 我们常常会看到类似于360.金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一 ...

  5. C语言实现通用数据结构的高效设计

    近期在阅读一个开源的C++代码.里面用到了大量的STL里面的东西.或许是自己一直用C而非常少用C++来实现算法的原因.STL里面大量的模板令人心烦.一直对STL的效率表示怀疑,但在网上搜到这样一个帖子 ...

  6. hdu 1007 最近点对问题(Splay解法)

    为什么要写这个题..经典啊,当然,别以为我用分治做的,不过主要思想还是那神奇的六个点共存(一个h*2h的矩形中最多能放下多少个点使得两两距离不超过h) 其实我是在这里看到的 http://commun ...

  7. leetcode回文子串拆分-最小拆分次数

    转载请注明来自souldak,微博:@evagle 上一篇是要输出所有的可能拆分,这回是要输出拆分次数最少的切割次数. 如果直接按照上一篇那么做的话,就会超时,因为我们在判断s[i][j]是否是回文的 ...

  8. Cocos2d-x 3.1.1 Lua实例-AccelerometerTest(重力加速计)

    Cocos2d-x 3.1.1 Lua实例-AccelerometerTest(重力加速计) 本篇博客介绍Cocos2d-x的第一个实例--重力加速计測试.效果图(注:这里无法模拟重力感应): --[ ...

  9. 使用notepad运行python

    Notepad++ 是一个开源的文本编辑器,功能强大而且使用方便,一般情况下,Notepad++作为代码查看器,很方便,但是每次要运行的时候,总是需要用右键打开其他的IDE来编译和运行,总有些不方便. ...

  10. uva 10003 Cutting Sticks(区间DP)

    题目连接:10003 - Cutting Sticks 题目大意:给出一个长l的木棍, 再给出n个要求切割的点,每次切割的代价是当前木棍的长度, 现在要求输出最小代价. 解题思路:区间DP, 每次查找 ...