策略模式,可以让物件在运作时更改其行为或算法,你可以透过切换策略物件来改变计有的功能,你需要实作一个介面来代表这个策略物件,然後在主要类别当中去引入这个策略物件,在需要变更时来切换策略物件,来达成不同状况下所需要的功能,就像是大头菜的铃钱有两种模式,一种是原本的铃钱,另一种则是过期後归零,这个铃钱运算的模式就可以抽离出来作为策略物件。
首先我们要定义策略的介面,这个介面我们会希望策略物件必须要实作铃钱运算(calculatePrice)的方法。
Strategy.php
/**
* Interface Strategy.
*/
interface Strategy
{
/**
* @return int
*/
public function calculatePrice(int $price, int $count): int;
}
再来要实践大头菜的策略模式,首先是正常状况下的大头菜,会直接拿铃钱价格、总数相成後即是铃钱总价,并且将其回传。
TurnipsStrategy.php
/**
* Class TurnipsStrategy.
*/
class TurnipsStrategy implements Strategy
{
/**
* @return int
*/
public function calculatePrice(int $price, int $count): int
{
return $price * $count;
}
}
至於坏掉的部分,只要大头菜坏掉就是卖不出去,所以不用进行任何运算,直接回传 0 铃钱即可。
SpoliedStrategy.php
/**
* Class SpoliedStrategy.
*/
class SpoliedStrategy implements Strategy
{
/**
* @return int
*/
public function calculatePrice(int $price, int $count): int
{
return 0;
}
}
最後实作大头菜物件,我们需要顺便把策略物件丢进去,如果在建立大头菜物件时没有指定策略物件,那麽预设就给予正常的策略物件,并且提供一个可以临时切换策略物件的方法,以及计算铃钱总价的方法,这个计算的方法是透过呼叫策略物件的方法来实践。
Turnips.php
/**
* Class Turnips.
*/
class Turnips
{
/**
* @var int
*/
protected int $price;
/**
* @var int
*/
protected int $count;
/**
* @var Strategy
*/
protected Strategy $strategy;
/**
* Turnips constructor.
*
* @param int $price
* @param int $count
* @param Strategy $strategy
*/
public function __construct(int $price, int $count, Strategy $strategy = null)
{
$this->price = $price;
$this->count = $count;
// 如果在建立大头菜物件时没有指定策略物件,那麽预设就给予正常的策略物件。
$this->strategy = empty($strategy) ? new TurnipsStrategy() : $strategy;
}
/**
* @param Strategy $strategy
*/
public function setStrategy(Strategy $strategy)
{
$this->strategy = $strategy;
}
/**
* @return int
*/
public function calculatePrice(): int
{
return $this->strategy->calculatePrice($this->price, $this->count);
}
}
最後我们要测试策略大头菜是否如预期的可以运行,我们接下来有一项测试分别是建立大头菜物件,并且给予预设正常的策略物件,正常情况下可以计算出铃钱,这时候把策略物件替换为坏掉的模式,再重复呼叫方法时,则是获得 0 铃钱。
StrategyPatternTest.php
/**
* Class StrategyPatternTest.
*/
class StrategyPatternTest extends TestCase
{
/**
* @test
*/
public function test_strategy()
{
$turnips = new Turnips(100, 40, new TurnipsStrategy);
$this->assertEquals(4000, $turnips->calculatePrice());
$turnips->setStrategy(new SpoliedStrategy());
$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 ✔
==> AbstractFactoryTest ✔ ✔ ✔ ✔
==> BuilderPatternTest ✔ ✔ ✔ ✔
==> FactoryMethodTest ✔ ✔ ✔ ✔
==> PoolPatternTest ✔ ✔
==> PrototypePatternTest ✔ ✔
==> SimpleFactoryTest ✔ ✔ ✔ ✔
==> SingletonPatternTest ✔
==> StaticFactoryTest ✔ ✔ ✔ ✔ ✔
==> AdapterPatternTest ✔ ✔
==> BridgePatternTest ✔ ✔ ✔
==> CompositePatternTest ✔ ✔ ✔
==> DataMapperTest ✔ ✔
==> DecoratorPatternTest ✔ ✔
==> DependencyInjectionTest ✔ ✔ ✔
==> FacadePatternTest ✔
==> FluentInterfaceTest ✔
==> FlyweightPatternTest ✔
==> ProxyPatternTest ✔ ✔
==> RegistryPatternTest ✔ ✔ ✔ ✔ ✔
Time: 00:00.084, Memory: 8.00 MB
OK (74 tests, 147 assertions)
<<: [Android 开发经验三十天]D29一小画家小问题跟改善方法
>>: Python API Lab 1.0 –增加更多API需求
自动更新每日个股日成交资讯 结合前几篇所学,我们来做一个可以自动更新日成交资讯的程序吧! Reque...
这篇会讲解怎麽样用 DOM 的 parser 把 RSS 资讯拿出来,首先我们可以先 new 一个 ...
在昨天的铁人贴文中制作了交易建立的画面,之前也有提到,透过批次,会於日档批次中,定期抓取历史缴费纪录...
今天的 Home 目录没有修改,https://github.com/simba-fs/2021-...
「错误」的定义 重复上章节对「好奇心」的心理假设: 大脑只有在感知到预测和实际认知有缺口时,才会启动...