<?php
/**
* 简单工厂的演变
*/
/**
* 引导
*
* 1、当看到 “new”, 就会想到具体。导致代码更脆弱更缺乏弹性。,使用接口让代码具有弹性。
* 2、针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。why?如果代码是针对接口而写,那么通过多态,它可以与任何新类实现该接口。
* 但是,当代码使用大量的具体类时,等于是自找麻烦,因为一旦加入新的具体类,就必须改变代码。也就是说,你的代码并非“对修改关闭”。想用新的具体类型来扩展代码,必须重新打开它。
* 3、从封装特性,中寻找线索,找出会变化的方面,把它们从不变的部分分离出来。
*/
/**
*
* 1、识别变化
*/
class PizzaStore {
public function orderPizza() {
//为了让系统有弹性,我们很希望这是一个抽象类或接口。
$pizza = new Pizza(); //变化部分
$pizza->prepare(); //准备
$pizza->bake(); //烘烤
$pizza->cut(); //切片
$pizza->box(); //包装
return $pizza;
}
}
/**
* 当需要更多Pizza 类型时。。。
* 必须添加一些代码,来“决定” 适合的比萨类型,然后再“制作”这个比萨。
*/
class PizzaStore {
public function orderPizza($type) {
if ("cheese" == $type) {//奶酪比萨
$pizza = new CheesePizza();
} elseif ("greek" == $type) {//希腊比萨
$pizza = new GreekPizza();
} elseif ("pepperoni" == $type) {//香肠比萨
$pizza = new PepperoniPizza();
} else {
//
}
$pizza->prepare();
$pizza->bake();
$pizza->cut();
$pizza->box();
return $pizza;
}
}
/**
* 明显可见,如果实例化“某些”具体类,将使orderPizza() 出现问题,而且也无法对orderPizza“修改关闭”。
* 但是,现在我们已经知道哪些会改变,哪些不会改变,该是使用封装的时候了。
*/
/**
* 封装创建对象的代码,创建比萨的代码转移到另一个对象中,由这个对象专职创建比萨。
* 该对象称为“工厂”。
*/
class SimpleFactory {
public function createPizza($type) {
if ("cheese" == $type) {//奶酪比萨
$pizza = new CheesePizza();
} elseif ("greek" == $type) {//希腊比萨
$pizza = new GreekPizza();
} elseif ("pepperoni" == $type) {//香肠比萨
$pizza = new PepperoniPizza();
} else {
//
}
return $pizza;
}
}
abstract class Pizza {
public $name;
public $price;
abstract public function perpare();
abstract public function bake();
abstract public function cut();
abstract public function box();
}
class CheesePizza extends Pizza {
public $name;
public $price;
public function __construct() {
$this->name = '奶酪比萨';
$this->price = '10';
}
public function perpare() {
}
public function bake() {
//TODO
}
public function cut() {
//TODO
}
public function box() {
//TODO
}
public function getName() {
return $this->name;
}
//其他行为操作省略
}
class GreekPizza extends Pizza {
public $name;
public $price;
public function __construct() {
$this->name = '希腊比萨';
$this->price = '5';
}
public function perpare() {
//TODO
}
public function bake() {
//TODO
}
public function cut() {
//TODO
}
public function box() {
//TODO
}
public function getName() {
return $this->name;
}
//其他行为操作省略
}
/**
* 问:我曾经看过一个类似的设计方式,把工厂定义成一个静态的方法。这有何差别?
* 答:利用静态方法定义一个简单的工厂,这是个常见的技巧,常被成为“静态工厂”。为何使用静态方法?因为不需要使用创建对象来实例化对象。
* 但请记住,这也有缺点,不能通过继承来改变创建方法的行为。
*/
/**
* 接下,重写PizzaStore 类.
* 我们所要做的是仰仗工厂来为我们创建比萨。
*/
class PizzaStore {
public $factory;
public function __construct(SimpleFactory $simpleFactory ) {
$this->factory = $simpleFactory;
}
public function orderPizza($type) {
//为了让系统有弹性,我们很希望这是一个抽象类或接口。
$pizza = $this->factory->createPizza($type); //变化部分
$pizza->perpare(); //准备
$pizza->bake(); //烘烤
$pizza->cut(); //切片
$pizza->box(); //包装
return $pizza;
}
}
$simpleFactory = new simpleFactory();
$pizzaStore = new PizzaStore($simpleFactory);
$pizza = $pizzaStore->orderPizza('cheese');
echo $pizza->name.":".$pizza->price;
/**
* 我们知道对象组合可以再运行时动态改变行为,因为我们可以更换不同的实现。在PizzaStore例子中要如何做到这点呢?有哪些工厂的实现能够被我们自由地更换?
*/
/**
* 总结:
*
* 简单工厂(simple factory)
* 1、simple factory 模式的工厂类根据提供给他的参数,返回几个可能产品类中的一个类的实例。通常它的返回的类都有一个公共的父类和公共的方法。
* 2、simple factory 模式实际上不是gof 23个设计模式中的一员,反而比较像是一种编程习惯,但由于经常被使用,给他一个”荣誉奖“。不要因为不是设计模式而忽略它的用法。
*
* 具体结构如下:
* -工厂类角色creator(SimpleFactory):工厂类在客户端直接控制下(create 方法)创建产品对象。
* -抽象产品角色product(pizza):定义简单工厂创建对象的父类或者它们的共同拥有的接口。可以使抽象类也可以是接口。
* -具体产品角色ConcreteProduct(CheesePizza) : 定义工厂创建的具体对象。
* -客户端client(PizzaStore):工厂客户,通过客户端方法调用工厂创建实例。
*/
更多精彩 在 工厂方法