1、模式定义

定义一个创建对象的接口,但是让子类去实例化具体类。工厂方法模式让类的实例化延迟到子类中。

2、问题引出

框架需要为多个应用提供标准化的架构模型,同时也要允许独立应用定义自己的域对象并对其进行实例化。

3、解决办法

工厂方法以模板方法的方式创建对象来解决上述问题。父类定义所有标准通用行为,然后将创建细节放到子类中实现并输出给客户端。

人们通常使用工厂模式作为创建对象的标准方式,但是在这些情况下不必使用工厂方法:实例化的类永远不会改变;或者实例化发生在子类可以轻易覆盖的操作中(比如初始化)。

4、UML类图

5、示例代码

FactoryMethod.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* 工厂方法抽象类
*/
abstract class FactoryMethod
{ const CHEAP = 1;
const FAST = 2; /**
* 子类必须实现该方法
*
* @param string $type a generic type
*
* @return VehicleInterface a new vehicle
*/
abstract protected function createVehicle($type); /**
* 创建新的车辆
*
* @param int $type
*
* @return VehicleInterface a new vehicle
*/
public function create($type)
{
$obj = $this->createVehicle($type);
$obj->setColor("#f00"); return $obj;
}
}

ItalianFactory.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* ItalianFactory是意大利的造车厂
*/
class ItalianFactory extends FactoryMethod
{
/**
* {@inheritdoc}
*/
protected function createVehicle($type)
{
switch ($type) {
case parent::CHEAP:
return new Bicycle();
break;
case parent::FAST:
return new Ferrari();
break;
default:
throw new \InvalidArgumentException("$type is not a valid vehicle");
}
}
}

GermanFactory.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* GermanFactory是德国的造车厂
*/
class GermanFactory extends FactoryMethod
{
/**
* {@inheritdoc}
*/
protected function createVehicle($type)
{
switch ($type) {
case parent::CHEAP:
return new Bicycle();
break;
case parent::FAST:
$obj = new Porsche();
//因为我们已经知道是什么对象所以可以调用具体方法
$obj->addTuningAMG(); return $obj;
break;
default:
throw new \InvalidArgumentException("$type is not a valid vehicle");
}
}
}

VehicleInterface.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* VehicleInterface是车辆接口
*/
interface VehicleInterface
{
/**
* 设置车的颜色
*
* @param string $rgb
*/
public function setColor($rgb);
}

Porsche.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* Porsche(保时捷)
*/
class Porsche implements VehicleInterface
{
/**
* @var string
*/
protected $color; /**
* @param string $rgb
*/
public function setColor($rgb)
{
$this->color = $rgb;
} /**
* 尽管只有奔驰汽车挂有AMG品牌,这里我们提供一个空方法仅作代码示例
*/
public function addTuningAMG()
{
}
}

Bicycle.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* Bicycle(自行车)
*/
class Bicycle implements VehicleInterface
{
/**
* @var string
*/
protected $color; /**
* 设置自行车的颜色
*
* @param string $rgb
*/
public function setColor($rgb)
{
$this->color = $rgb;
}
}

Ferrari.php

<?php

namespace DesignPatterns\Creational\FactoryMethod;

/**
* Ferrari(法拉利)
*/
class Ferrari implements VehicleInterface
{
/**
* @var string
*/
protected $color; /**
* @param string $rgb
*/
public function setColor($rgb)
{
$this->color = $rgb;
}
}

6、测试代码

Tests/FactoryMethodTest.php

<?php

namespace DesignPatterns\Creational\FactoryMethod\Tests;

use DesignPatterns\Creational\FactoryMethod\FactoryMethod;
use DesignPatterns\Creational\FactoryMethod\GermanFactory;
use DesignPatterns\Creational\FactoryMethod\ItalianFactory; /**
* FactoryMethodTest用于测试工厂方法模式
*/
class FactoryMethodTest extends \PHPUnit_Framework_TestCase
{ protected $type = array(
FactoryMethod::CHEAP,
FactoryMethod::FAST
); public function getShop()
{
return array(
array(new GermanFactory()),
array(new ItalianFactory())
);
} /**
* @dataProvider getShop
*/
public function testCreation(FactoryMethod $shop)
{
// 该方法扮演客户端角色,我们不关心什么工厂,我们只知道可以可以用它来造车
foreach ($this->type as $oneType) {
$vehicle = $shop->create($oneType);
$this->assertInstanceOf('DesignPatterns\Creational\FactoryMethod\VehicleInterface', $vehicle);
}
} /**
* @dataProvider getShop
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage spaceship is not a valid vehicle
*/
public function testUnknownType(FactoryMethod $shop)
{
$shop->create('spaceship');
}
}

7、总结

工厂方法模式和抽象工厂模式有点类似,但也有不同。

工厂方法针对每一种产品提供一个工厂类,通过不同的工厂实例来创建不同的产品实例,在同一等级结构中,支持增加任意产品。

抽象工厂是应对产品族概念的,比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。

PHP 设计模式系列 —— 工厂方法模式(Factory Method)(转)的更多相关文章

  1. 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)

    原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...

  2. 设计模式-03工厂方法模式(Factory Method Pattern)

    插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...

  3. 【设计模式】工厂方法模式 Factory Method Pattern

    在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...

  4. 二十四种设计模式:工厂方法模式(Factory Method Pattern)

    工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...

  5. 设计模式之工厂方法模式(Factory Method Pattern)

    一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...

  6. 设计模式之 - 工厂方法模式 (Factory Method design pattern)

    1. 模式意图:  定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...

  7. 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源

    概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...

  8. 工厂方法模式-Factory Method(Java实现)

    工厂方法模式-Factory Method 工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法让实例化的具体内容交给子类工厂来进行. 本文中的例子是这样的. 生产一个身份证, ...

  9. 浅谈C++设计模式之工厂方法(Factory Method)

    为什么要用设计模式?根本原因是为了代码复用,增加可维护性. 面向对象设计坚持的原则:开闭原则(Open Closed Principle,OCP).里氏代换原则(Liskov Substitution ...

随机推荐

  1. 在Eclipse中无法链接到svn,出现Previous operation has not finished; run 'cleanup' if it was interrupted异常

    由于使用了clean或是clean up导致和svn断开链接 1.下载一个sqlite3.exe 2.将sqlite3.exe放到本项目的.svn同级目录下(.svn默认是隐藏,让.svn文件夹显示查 ...

  2. 解决 TCP_socket 粘包问题

    所谓粘包问题主要还是C/S两端数据传输时 因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的 根本原因:粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多 ...

  3. PowerShell使用教程

    一.说明 1.1 背景说明 个人对PowerShell也不是很熟悉,开始的时候就突然看到开始菜单中多了个叫PowerShell的文件夹,后来一点就看到某个教程视频说PowerShell很厉害但也没怎么 ...

  4. CentOS中/英文环境切换教程(CentOS6.8)

    一.前言 对于不习惯英文的人可能想将系统由英文转成中文:而对于考虑客户端如果没正确配置,中文目录可能显示为乱码的人则可能宁愿将系统由中文转成英文. 中文切换为英文,实际就是将LANG的值由zh_CN- ...

  5. Windows和Linux创建软链接和硬链接

    1.Wondows创建软链接和硬链接 mklink [/d] [/h] link target /d--创建目录软链接:默认为文件软链接:创建目录链接时必须使用该选项不然创出的软链接无效 /h--创建 ...

  6. Xmind settings lower

    Xmind settings lower   1● setting 2● options 3● fast short keys     快捷键(Windows) 快捷键(Mac) 描述 Ctrl+N ...

  7. 重绘(Repaint)和回流(Reflow)

    重绘(Repaint)和回流(Reflow) 1.回流和重绘只是渲染步骤的一小节,是怎么做到影响性能的? css 会影响 javascrip 执行时间导致 javascript 脚本变慢 浏览器渲染一 ...

  8. java中JDBC连接数据库操作的基本步骤

    JDBC基本步骤 创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lan ...

  9. flask项目结构(一)mariadb

    简介: 本文主要是根据自己所学,创建一个flask项目,使用sqlalchemy,alembic,mariadb,bootstrap,APScheduler,selenium,request…………技 ...

  10. Java实现将数字转为大写汉字

    public class Int2Big { static String int2big(int src) { final String num[] = {"零", "壹 ...