工厂模式--工厂方法

工厂方法模式

所有的工厂方法都是用来封装和创建对象,先看下工厂方法的定义:

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法把类的实例化推迟到子类。

在开始下面的代码故事之前,我还是希望你看一下我的上一篇,简单工厂,看一下我现在店铺的规模和经营方式。

我这里还是想要开一家披萨店,上海必败客披萨(SHBBK),来自纽约的一个有钱人想要加盟我的披萨店,他希望同时提供纽约风味的披萨。按照我已经实现的简单工厂方式,我就需要增加一个店铺:NYBBKPizza,这个店铺的运营方式同BBKPizza一样:
在这里插入图片描述同时,我还修改简单工厂,增加对纽约口味披萨的判断。到目前为止,店铺还能勉强经营。2个月后,纽约的店铺私自修改的orderPizza和Pizza,纽约人不喜欢把披萨切片,所以他们删掉了cut()方法,他们还在披萨中加入了本地的特产的披萨,这显然是我不能容忍的。我需要控制披萨本身,同时我还要控制生产和订购披萨的过程。必须快速解决这个问题,因为来自巴黎的一个有钱人又要加盟我的店铺了。

相比于讲故事,我觉得画图还是更快的
先看Pizza,各种风味的pizza全部在国内生产:
纽约口味、上海口味等
对于工厂,我这里改变了方式
在这里插入图片描述
PizzaStore规定的生产披萨和订购披萨的方式,允许各个工厂生产自己的特色披萨,比如上海必败客生成上海本地的披萨。

来看PizzaStore

<?php
namespace FactoryMethod;

/**
 * 所有工厂模式都是用来封装对象的创建。工厂方法,让子类决定创建的具体对象
 *
 * Class PizzaFactory
 * @package FactoryMethod
 */
abstract class PizzaFactory
{
    /**
     *  不希望被重写,防止被子类覆盖
     *
     * @param $type
     */
    public final function orderPizza($type){
        $pizza = $this->createPizza($type);

        // 解耦,orderPizza并不知道具体哪个Pizza进来了
        $pizza->prepare();
        $pizza->cut();
        $pizza->box();
    }

    /**
     *  工厂方法,把创建具体对象的过程延迟到子类
     *
     * @param $type
     * @return Pizza
     */
    abstract function createPizza($type):Pizza;
}

SHBBK工厂是这样的:

<?php

namespace FactoryMethod;
/**
 *  上海的必败客披萨工厂
 *
 * Class BBkFactorySH
 * @package FactoryMethod
 */
class BBkFactorySH extends PizzaFactory
{
    public function createPizza($type): Pizza {
        $pizza = null;
        if (0==strcmp($type, 'shang_hai')) {
            $pizza = new PizzaShangHai();
            // 不喜欢构造函数,所以没用
            $pizza->setName('上海杏花楼');
        }elseif(0==strcmp($type,'niu_yue')){
            $pizza=new PizzaNYStyle();
            $pizza->setName('上海纽约风味');
        }
        return $pizza;
    }
}

还有Pizza本身:

<?php

namespace FactoryMethod;

/**
 *  披萨类
 *
 * Class Pizza
 * @package FactoryMethod
 */
class Pizza
{
    protected $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function prepare() {
        echo $this->name . '正在准备披萨...';
        echo '<br>';
    }

    public function cut() {
        echo $this->name . '披萨切片...';
        echo '<br>';
    }

    public function box() {
        echo $this->name . '披萨打包完毕';
        echo '<br>';
    }
}

上海本地特色披萨:PizzaShangHai

<?php
namespace FactoryMethod;

/**
 *  具有上海特色的披萨
 *
 * Class PizzaShangHai
 * @package FactoryMethod
 */
class PizzaShangHai extends Pizza
{

}

纽约本地特色披萨:PizzaNYStyle

<?php
namespace FactoryMethod;
/**
 *  具有纽约特色的披萨
 *
 * Class PizzaNYStyle
 * @package FactoryMethod
 */
class PizzaNYStyle extends Pizza
{

}

好了,是时候来点个披萨了:

<?php
include 'Pizza.php';
include 'PizzaFactory.php';
include 'BBkFactorySH.php';
include 'PizzaNYStyle.php';
include 'PizzaShangHai.php';

use FactoryMethod\BBkFactorySH;

$bbk_sh = new BBkFactorySH();

$bbk_sh->orderPizza('shang_hai');

在这里插入图片描述
设计原则:

要依赖抽象,不要依赖具体类

它有一个响亮的名字:依赖倒置原则

这个很像之前提到的:

针对接口编程,而不是针对实现编程

这里更强调的抽象,即不能让高层组件依赖底层组件,不管高层组件和底层组件,他们都应该依赖抽象(这里的PizzaFactory是高层组件PizzaShangHai就是底层的组件)。披萨店铺需要提供披萨,芝士披萨、大虾披萨都是披萨,所以所有的披萨都应该共享一个Pizza入口,芝士披萨,大虾披萨都讲依赖于Pizza,而店铺也不需理会具体的Pizza,它只需要依赖Pizza即可,这就是依赖倒置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值