【PHP 设计模式大头菜】模板方法 Template Method

Banner

模板方法 Template Method

模板方法,是一种如果这包水泥我有、你也有,就连乔瑟夫都有,那我们就应该把这八百包水泥抽离出来的设计模式,是设计模式中很简单的模式,在模板(Template)里头会定义需要实作的方法,并且由继承物件去实作或复写,这个设计模式适用於不同物件有多处相似功能的时候,可以减少物件的耦合性过高问题。

UML

UML

实作

首先我们会需要建立一个抽象的模板,并且提供大头菜无论健康的、坏掉的都拥有的方法,像是获得铃钱价格(getPrice)、获得数量(getCount)以及计算总计铃钱价格(calculatePrice),而有些方法需要继承物件去实作的,例如设定铃钱价格(setPrice),我们就需要以抽象方法的方式去定义,让继承物件必须去实作。

TurnipsTemplate.php

/**
 * Abstract TurnipsTemplate.
 */
abstract class TurnipsTemplate
{
    /**
     * @var int
     */
    protected int $price = 0;

    /**
     * @var int
     */
    protected int $count = 0;

    /**
     * TurnipsTemplate constructor.
     * 
     * @param int $price
     * @param int $count
     */
    public function __construct(int $price, int $count)
    {
        $this->setPrice($price);
        $this->setCount($count);
    }

    /**
     * @return int
     */
    public function getPrice()
    {
        return $this->price;
    }

    /**
     * @return int
     */
    public function getCount()
    {
        return $this->count;
    }

    /**
     * @param int $price
     */
    abstract public function setPrice(int $price);

    /**
     * @param int $count
     */
    public function setCount(int $count)
    {
        $this->count = $count;
    }

    /**
     * @return int
     */
    public function calculatePrice(): int
    {
        $price = $this->price;
        $count = $this->count;
        return $price * $count;
    }
}

再来我们开始建立物件去继承模板,首先健康的大头菜,在设定铃钱价格时,就直接根据设定的铃钱金额去如实设定。

Turnips.php

/**
 * Class Turnips.
 */
class Turnips extends TurnipsTemplate
{
    /**
     * @param int $price
     */
    public function setPrice(int $price)
    {
        $this->price = $price;
    }
}

而坏掉的大头菜部分,则是无论设定的铃钱金额是多少,都要直接给予 0 铃钱,因为坏掉的大头菜不值任何铃钱。

Spoiled.php

/**
 * Class Spoiled.
 */
class Spoiled extends TurnipsTemplate
{
    /**
     * @param int $price
     */
    public function setPrice(int $price)
    {
        $this->price = 0;
    }
}

测试

最终我们要测试大头菜的模板所建构出来的大头菜物件是否可以正常运作,我们会有两个测试,分别是测试健康的大头菜物件(Turnips)以及坏掉的大头菜物件(Spoiled)。

TemplateMethodTest.php

/**
 * Class TemplateMethodTest.
 */
class TemplateMethodTest extends TestCase
{
    /**
     * @test
     */
    public function test_turnips_template()
    {
        $turnips = new Turnips(100, 40);

        $this->assertEquals(100, $turnips->getPrice());
        $this->assertEquals(40, $turnips->getCount());
        $this->assertEquals(4000, $turnips->calculatePrice());
    }

    /**
     * @test
     */
    public function test_spoiled_template()
    {
        $turnips = new Spoiled(100, 40);

        $this->assertEquals(0, $turnips->getPrice());
        $this->assertEquals(40, $turnips->getCount());
        $this->assertEquals(0, $turnips->calculatePrice());
    }
}

最後测试的执行结果会获得如下:

PHPUnit Pretty Result Printer 0.28.0 by Codedungeon and contributors.
==> Configuration: ~/php-design-pattern/vendor/codedungeon/phpunit-result-printer/src/phpunit-printer.yml

PHPUnit 9.2.6 by Sebastian Bergmann and contributors.


 ==> ...fResponsibilitiesTest   ✔  ✔  ✔  
 ==> CommandPatternTest         ✔  
 ==> IteratorPatternTest        ✔  ✔  ✔  ✔  
 ==> MediatorPatternTest        ✔  ✔  ✔  
 ==> MementoPatternTest         ✔  
 ==> NullObjectPatternTest      ✔  ✔  ✔  ✔  
 ==> ObserverPatternTest        ✔  
 ==> SpecificationPatternTest   ✔  ✔  ✔  ✔  
 ==> StatePatternTest           ✔  
 ==> StrategyPatternTest        ✔  
 ==> TemplateMethodTest         ✔  ✔  
 ==> AbstractFactoryTest        ✔  ✔  ✔  ✔  
 ==> BuilderPatternTest         ✔  ✔  ✔  ✔  
 ==> FactoryMethodTest          ✔  ✔  ✔  ✔  
 ==> PoolPatternTest            ✔  ✔  
 ==> PrototypePatternTest       ✔  ✔  
 ==> SimpleFactoryTest          ✔  ✔  ✔  ✔  
 ==> SingletonPatternTest       ✔  
 ==> StaticFactoryTest          ✔  ✔  ✔  ✔  ✔  
 ==> AdapterPatternTest         ✔  ✔  
 ==> BridgePatternTest          ✔  ✔  ✔  
 ==> CompositePatternTest       ✔  ✔  ✔  
 ==> DataMapperTest             ✔  ✔  
 ==> DecoratorPatternTest       ✔  ✔  
 ==> DependencyInjectionTest    ✔  ✔  ✔  
 ==> FacadePatternTest          ✔  
 ==> FluentInterfaceTest        ✔  
 ==> FlyweightPatternTest       ✔  
 ==> ProxyPatternTest           ✔  ✔  
 ==> RegistryPatternTest        ✔  ✔  ✔  ✔  ✔  

Time: 00:00.052, Memory: 8.00 MB

OK (76 tests, 153 assertions)

完整程序码

设计模式不难,找回快乐而已,以大头菜为例。

参考文献


<<:  [Day28] Advanced Watcher

>>:  Outlook 2007常见问题 - 整理常被问到的案件

[WMX3] 7.IO - Set/Get OutBytes

在还没开始撰写程序前可以先开启WMX3 Console选取I/O 图上显示的红底0.0第一个字代表位...

Day 20 舍弃Storyboard并使用XIB来写app

虽然storyboard是个对初学者比较方便使用的东西,但是当你有很多元件要用,修改来讲的话就就会比...

Day 4 资讯结构与阶层分析- (main content + footer)

延续上回~~ 四、再往底下看是主要的Main Content,也就是对於使用者来说目光会停留最久的区...

Day 27 Spark local mode

Spark local mode Environment Ubuntu HP Z230 数量: 1 ...

Day12:字典(dictionary)

壹、Python 创建字典(dictionary)的方式有两种: 1.使用 {} [In] pric...