视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
一文读懂php设计模式之模板方法模式
2020-11-02 18:30:00 责编:小采
文档

模板方法模式也是一种常用的设计模式,它属于行为性设计模式。它的定义是:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

场景

一般周末早上起来比较晚,就不会出去买早点吃,可能就会泡一桶方便面或酸辣粉或淮南牛肉汤。泡方便面或酸辣粉的步骤是一样的,首先需要准备开水,然后用开水泡方便面或酸辣粉,接下来加入自己的调料包,最后泡上2~3分钟就行了。这中间有两个步骤完全一致(准备开水、泡2~3分钟)、有两个步骤类似(泡食材、加入各自调料包)。

对于上面的场景,我们可以定义一个泡方便面或酸辣粉的算法。这个算法非常简单,4个步骤

  • 准备开水

  • 泡食材(方便面或酸辣粉)

  • 加调料(方便面、酸辣粉有自己的调料包)

  • 在开水中浸泡2~3分钟

  • 现在,我们用模板方法模式来完成上述需求。

    首先,定义一个抽象类,抽象类里定义具体的算法,以及各个步骤。

    abstract class Breakfast
    {
     final public function prepare () {
     $this->boilWater();
     $this->brew();
     $this->addSeasoning(); 
     $this->wait();
     }
     
     public function boilWater ()
     {
     echo '准备开水' . PHP_EOL;
     }
     
     // 泡食材
     abstract public function brew ();
     
     // 加调料
     abstract public function addSeasoning ();
     
     public function wait ()
     {
     echo '等待2~3分钟' . PHP_EOL;
     }
    }

    prepare方法里就是具体的算法,给这个方法加上final是防止该方法被重写。另外,你可以看到这里面有两个抽象方法,需要后代去自行完成。

    接下来,我们来完成方便面及酸辣粉的类。这两个类需继承Breakfast,然后完成抽象方法。

    class Noodle extends Breakfast
    {
     public function brew ()
     {
     echo '加入方便面' . PHP_EOL;
     }
     public function addSeasoning ()
     {
     echo '加入方便面的调料包' . PHP_EOL;
     }
    }
    
    class Powder extends Breakfast
    {
     public function brew ()
     {
     echo '加入酸辣粉' . PHP_EOL;
     }
     public function addSeasoning ()
     {
     echo '加入酸辣粉的调料包' . PHP_EOL;
     }
    }

    上述的例子就是一个典型的模板方法模式,父类里定义算法骨架,子类完成算法中的一些步骤。

    钩子

    上述的例子,体现了模板方法模式中一个常用场景:复用。除了复用外,模板方法模式还是一个重要的应用——扩展。

    模板方法模式是通过钩子来实现扩展的。钩子是一种声明在抽象类中的方法,但只有空的或默认的实现。钩子的存在,让子类有能力对算法不同点进行挂钩。要不要挂钩,由子类自己决定。

    下面我们继续通过例子来讲解钩子的使用,一般我吃泡面的时候,会加火腿或鸡蛋。加火腿和鸡蛋这个是不确定的,所以我们可以钩子,让子类自己决定要不要加火腿或鸡蛋。

    修改Breakfast.php

    abstract class Breakfast
    {
     final public function prepare () {
     $this->boilWater();
     $this->brew();
     $this->addSeasoning();
     $this->hook();
     $this->wait();
     }
     
     
     // 省略部分方法
     
     
     // 默认不做任何事情
     public function hook () :void
     {}
    }

    修改Noodle.php,重写hook方法

    public function hook(): void
    {
     echo '加入火腿和鸡蛋' . PHP_EOL;
    }

    模板方法模式与回调函数

    php中有许多的函数用了类似模板方法模式或策略模式的思想,比如sort()函数,它封装了排序的算法,但是具体的排序规则,由回调函数去完成。通过回调函数就不用去创建抽象类以及子类了,大大的减少了代码量。

    模板方法模式与工厂方法模式、策略模式的关系

    工厂方法模式时模板方法模式一个特殊的形式。

    模板方法基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。

    策略模式基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。

    模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作, 因此允许在运行时切换行为。

    下载本文
    显示全文
    专题