PHP 设计模式系列 -- 规格模式(Specification)
程序员文章站
2024-01-01 14:10:22
...
1、模式定义
规格模式(Specification)可以认为是组合模式的一种扩展。有时项目中某些条件决定了业务逻辑,这些条件就可以抽离出来以某种关系(与、或、非)进行组合,从而灵活地对业务逻辑进行定制。另外,在查询、过滤等应用场合中,通过预定义多个条件,然后使用这些条件的组合来处理查询或过滤,而不是使用逻辑判断语句来处理,可以简化整个实现逻辑。
这里的每个条件就是一个规格,多个规格/条件通过串联的方式以某种逻辑关系形成一个组合式的规格。
2、UML类图
3、示例代码
Item.php
price = $price; } /** * Get the items price * * @return int */ public function getPrice() { return $this->price; }}
SpecificationInterface.php
AbstractSpecification.php
Plus.php
left = $left; $this->right = $right; } /** * 返回两种规格的逻辑与评估 * * @param Item $item * * @return bool */ public function isSatisfiedBy(Item $item) { return $this->left->isSatisfiedBy($item) && $this->right->isSatisfiedBy($item); }}Either.php
left = $left; $this->right = $right; } /** * 返回两种规格的逻辑或评估 * * @param Item $item * * @return bool */ public function isSatisfiedBy(Item $item) { return $this->left->isSatisfiedBy($item) || $this->right->isSatisfiedBy($item); }}Not.php
spec = $spec; } /** * 返回规格的相反结果 * * @param Item $item * * @return bool */ public function isSatisfiedBy(Item $item) { return !$this->spec->isSatisfiedBy($item); }}PriceSpecification.php
maxPrice = $maxPrice; } /** * 设置最小值 * * @param int $minPrice */ public function setMinPrice($minPrice) { $this->minPrice = $minPrice; } /** * 判断给定Item的定价是否在最小值和最大值之间 * * @param Item $item * * @return bool */ public function isSatisfiedBy(Item $item) { if (!empty($this->maxPrice) && $item->getPrice() > $this->maxPrice) { return false; } if (!empty($this->minPrice) && $item->getPrice() minPrice) { return false; } return true; }}4、测试代码
Tests/SpecificationTest.php
assertTrue($spec->isSatisfiedBy($item)); $spec->setMaxPrice(50); $this->assertFalse($spec->isSatisfiedBy($item)); $spec->setMaxPrice(150); $this->assertTrue($spec->isSatisfiedBy($item)); $spec->setMinPrice(101); $this->assertFalse($spec->isSatisfiedBy($item)); $spec->setMinPrice(100); $this->assertTrue($spec->isSatisfiedBy($item)); } public function testNotSpecification() { $item = new Item(100); $spec = new PriceSpecification(); $not = $spec->not(); $this->assertFalse($not->isSatisfiedBy($item)); $spec->setMaxPrice(50); $this->assertTrue($not->isSatisfiedBy($item)); $spec->setMaxPrice(150); $this->assertFalse($not->isSatisfiedBy($item)); $spec->setMinPrice(101); $this->assertTrue($not->isSatisfiedBy($item)); $spec->setMinPrice(100); $this->assertFalse($not->isSatisfiedBy($item)); } public function testPlusSpecification() { $spec1 = new PriceSpecification(); $spec2 = new PriceSpecification(); $plus = $spec1->plus($spec2); $item = new Item(100); $this->assertTrue($plus->isSatisfiedBy($item)); $spec1->setMaxPrice(150); $spec2->setMinPrice(50); $this->assertTrue($plus->isSatisfiedBy($item)); $spec1->setMaxPrice(150); $spec2->setMinPrice(101); $this->assertFalse($plus->isSatisfiedBy($item)); $spec1->setMaxPrice(99); $spec2->setMinPrice(50); $this->assertFalse($plus->isSatisfiedBy($item)); } public function testEitherSpecification() { $spec1 = new PriceSpecification(); $spec2 = new PriceSpecification(); $either = $spec1->either($spec2); $item = new Item(100); $this->assertTrue($either->isSatisfiedBy($item)); $spec1->setMaxPrice(150); $spec2->setMaxPrice(150); $this->assertTrue($either->isSatisfiedBy($item)); $spec1->setMaxPrice(150); $spec2->setMaxPrice(0); $this->assertTrue($either->isSatisfiedBy($item)); $spec1->setMaxPrice(0); $spec2->setMaxPrice(150); $this->assertTrue($either->isSatisfiedBy($item)); $spec1->setMaxPrice(99); $spec2->setMaxPrice(99); $this->assertFalse($either->isSatisfiedBy($item)); }}