PHP设计模式(三)之工厂方法模式

作者: 温新

分类: 【设计模式】

阅读: 3005

时间: 2019-12-11 17:45:17

一、什么是工厂方法模式

1)工厂方法模式(Factory Method Pattern),又称 多态性工厂模式(Polymorphic Factory)

2)工厂方法模式就是为每一个产品提供独立的工厂类,根据不同的工厂实例来生产不同的产品。

二、工厂方法模式结构

Product抽象产品定义子类要实现的产品接口方法

ConcreteProduct 具体产品实现抽象产品中定义的产品,且工厂方法模式创建的每一个产品都是具体产品的实例

Factory 抽象工厂工厂方法模式的核心所在,其定义了具体工厂所要实现的具体产品接口(这一步是核心)

ConcreteFactory 具体工厂

案例归纳

// 产品接口
interface product
{
    public function getProduct();
}

// 具体产品

class specificProduct implements product
{
    public function getProduct()
    {
        echo 'product';
    }
}

// 工厂接口

interface factory
{
    public function product();
}

// 具体工厂
class specificFactory implements factory
{
    public function getFactory()
    {
        return new specificProduct();
    }
}

三、工厂方法模式的优缺点

优点

1)具有良好的封装性。调用产品只需要从工厂中获取即可。

2)易扩展。曾加产品时,只需要添加添加产品类(扩展),不用修改核心代码。

3)屏蔽产品类,解除耦合。

缺点

每新增一个产品时就要新增一个具体产品类与具体工厂类,增加了系统的复杂度

四、简单工厂模式与工厂方法模式对比

简单工厂方法模式

新增产品类时,需要修改核心工厂类,不仅破坏了开闭原则而且当产品达到一定的数量时,难以维护。

工厂方法模式

把创建产品的工作交给子类工厂来做,当新增产品时,只需要新增产品类即可,解决了简单工厂方法模式修改核心代码的缺点,且易于扩展。

五、举例说明

从上一篇的简单工厂模式说明,目前餐厅有两个菜品,分别是酸辣土豆丝、鱼香茄子。为了吸引顾客,餐馆不断创新,推出新的菜品,如新增麻婆豆腐、番茄炒鸡蛋...众多菜品,这就使得餐厅工厂核心类不断扩大,达到一定量级时难以维护,且修改核心部件容易出错,为了解决这个问题,餐馆老板想到一个解决办法,把核心独立出来,新增餐品时,我只要在核心工厂中定义新的菜名,其他的则由子类工厂来实现,这样不是更好吗?这就是工厂方法模式。

解释:

1)上面独立出来的工厂接口可以看作是一个实体工厂,它只需要定义哪些是必须要实现的菜品,它的任务就是把要做的告诉工厂车间

2)具体工厂类可以看作是实体工厂的每一个车间,它来实际生产产品。

六、代码实现

// Ps:这个接口是工厂方法模式的核心 RestaurantMethodFactoryInterface.php

<?php
/**
 * 核心工厂接口
 */
interface RestaurantMethodFactoryInterface
{
    // 生产产品接口
    public function makeCookDish();
}

CookInterface.php

<?php

/**
 * 烹饪核心菜品接口,规定做菜的步骤
 */
interface Cook
{
    // 准备食材
    public function prepareIngredients();

    // 烹饪食材
    public function cooking();

    // 上菜
    public function serving();

}

BlackBean.php

<?php
/**
 * 酸辣土豆丝菜品
 */

class BlackBean implements Cook
{
    // 准备食材
    public function prepareIngredients()
    {
        echo '步骤一:准备食材:土豆、花椒、白醋、盐、干辣椒、葱蒜...';
    }

    // 烹饪食材
    public function cooking()
    {
        echo '步骤二:烹饪食材:土豆切丝去除淀粉,锅中水开,土豆入水10s捞出...';
    }

    // 上菜
    public function serving()
    {
        echo '步骤三:上菜:你的酸辣土豆丝来了~~';
    }   
}

Eggplant.php

<?php
/**
 * 鱼香茄子类菜品
 */

class Eggplant implements Cook
{
    // 准备食材
    public function prepareIngredients()
    {
        echo '步骤一:准备食材:茄子、葱姜蒜、豆瓣酱、水淀粉...';
    }

    // 烹饪食材
    public function cooking()
    {
        echo '步骤二:烹饪食材:锅内放油,放入肉糜煸炒,然后下葱姜蒜、豆瓣酱一起炒香....把茄子也一起放下去煮';
    }

    // 上菜
    public function serving()
    {
        echo '步骤三:上菜:你的鱼香茄子来了~~';
    }

}

BlackBeanFactory.php

<?php
/**
 * 酸辣土豆丝工厂
 */

class BlackBeanFactory implements RestaurantMethodFactoryInterface
{
    // 生产酸辣土豆丝
    public function makeCookDish()
    {
        return new BlackBean();
    }
}

EggplantFactroy.php

<?php
/**
 * 鱼香茄子工厂
 */

class EggplantFactroy implements RestaurantMethodFactoryInterface
{
    // 生产鱼香茄子
    public function makeCookDish()
    {
        return new Eggplant();
    }
}

// 这是新增的麻婆豆腐 MapoTuFu.php

<?php
/**
 * 麻婆豆腐菜品
 */

class MapoTuFu implements Cook
{
    // 准备食材
    public function prepareIngredients()
    {
        echo '步骤一:准备食材:豆腐、豆瓣、水淀粉...';
    }

    // 烹饪食材
    public function cooking()
    {
        echo '步骤二:烹饪食材:锅中热油,放入豆瓣炒香...';
    }

    // 上菜
    public function serving()
    {
        echo '步骤三:上菜:你的麻辣豆腐来了~~';
    }   
}

MapoTuFuFactory.php

<?php
/**
 * 麻婆豆腐工厂
 */

class MapoTuFuFactory implements RestaurantMethodFactoryInterface
{
    // 生产麻婆豆腐
    public function makeCookDish()
    {
        // 开始生产菜品(实例化菜品类)
        return new MapoTuFu();
    }
}

index.php

<?php
/**
 * 餐厅
 */
require_once './CookInterface.php';
require_once './RestaurantMethodFactoryInterface.php';
require_once './EggplantFactroy.php';
require_once './Eggplant.php';

// 鱼香茄子
require_once './MapoTuFuFactory.php';
require_once './MapoTuFu.php';
// 生产鱼香茄子
$maPoTuFuFactory = new MapoTuFuFactory();
$maPoTuFuProduct = $maPoTuFuFactory->makeCookDish();
// 准备食材
$maPoTuFu        = $maPoTuFuProduct->prepareIngredients();
// 烹饪食材
$maPoTuFu        = $maPoTuFuProduct->cooking();
// 你的鱼香茄子来了
$maPoTuFu        = $maPoTuFuProduct->serving();
print_r($maPoTuFu);

至此,工厂方法模式完毕,^_^ 对比简单工厂模式与工厂方法模式,优缺点一目了然。

我是夕阳何处寻,期待和优秀的你一起同行!

夕阳何处寻

2019年12月11日

请登录后再评论