PHP 设计模式系列之 specification规格模式


Posted in PHP onJanuary 10, 2016

1、模式定义

规格模式是组合模式的一种扩展,在框架性开发中使用较多(项目级开发很少使用),这里做一个简单的介绍。
规格模式(Specification)可以认为是组合模式的一种扩展。有时项目中某些条件决定了业务逻辑,这些条件就可以抽离出来以某种关系(与、或、非)进行组合,从而灵活地对业务逻辑进行定制。另外,在查询、过滤等应用场合中,通过预定义多个条件,然后使用这些条件的组合来处理查询或过滤,而不是使用逻辑判断语句来处理,可以简化整个实现逻辑。

这里的每个条件就是一个规格,多个规格/条件通过串联的方式以某种逻辑关系形成一个组合式的规格。

2、UML类图

PHP 设计模式系列之 specification规格模式

3、示例代码

Item.php

<?php
namespace DesignPatterns\Behavioral\Specification;
class Item
{
protected $price;

/**
* An item must have a price
*
* @param int $price
*/
public function __construct($price)
{
$this->price = $price;
}
/**
* Get the items price
*
* @return int
*/
public function getPrice()
{
return $this->price;
}
}

SpecificationInterface.php

<?php
namespace DesignPatterns\Behavioral\Specification;
/**
* 规格接口
*/
interface SpecificationInterface
{
/**
* 判断对象是否满足规格
*
* @param Item $item
*
* @return bool
*/
public function isSatisfiedBy(Item $item);

/**
* 创建一个逻辑与规格(AND)
*
* @param SpecificationInterface $spec
*/
public function plus(SpecificationInterface $spec);
/**
* 创建一个逻辑或规格(OR)
*
* @param SpecificationInterface $spec
*/
public function either(SpecificationInterface $spec);

/**
* 创建一个逻辑非规格(NOT)
*/
public function not();
}

AbstractSpecification.php

<?php
namespace DesignPatterns\Behavioral\Specification;

/**
* 规格抽象类
*/
abstract class AbstractSpecification implements SpecificationInterface
{
/**
* 检查给定Item是否满足所有规则
*
* @param Item $item
*
* @return bool
*/
abstract public function isSatisfiedBy(Item $item);
/**
* 创建一个新的逻辑与规格(AND)
*
* @param SpecificationInterface $spec
*
* @return SpecificationInterface
*/
public function plus(SpecificationInterface $spec)
{
return new Plus($this, $spec);
}
/**
* 创建一个新的逻辑或组合规格(OR)
*
* @param SpecificationInterface $spec
*
* @return SpecificationInterface
*/
public function either(SpecificationInterface $spec)
{
return new Either($this, $spec);
}
/**
* 创建一个新的逻辑非规格(NOT)
*
* @return SpecificationInterface
*/
public function not()
{
return new Not($this);
}
}

Plus.php

<?php
namespace DesignPatterns\Behavioral\Specification;
/**
* 逻辑与规格(AND)
*/
class Plus extends AbstractSpecification
{
protected $left;
protected $right;

/**
* 在构造函数中传入两种规格
*
* @param SpecificationInterface $left
* @param SpecificationInterface $right
*/
public function __construct(SpecificationInterface $left, SpecificationInterface $right)
{
$this->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

<?php
namespace DesignPatterns\Behavioral\Specification;

/**
* 逻辑或规格
*/
class Either extends AbstractSpecification
{

protected $left;
protected $right;
/**
* 两种规格的组合
*
* @param SpecificationInterface $left
* @param SpecificationInterface $right
*/
public function __construct(SpecificationInterface $left, SpecificationInterface $right)
{
$this->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

<?php
namespace DesignPatterns\Behavioral\Specification;

/**
* 逻辑非规格
*/
class Not extends AbstractSpecification
{
protected $spec;
/**
* 在构造函数中传入指定规格
*
* @param SpecificationInterface $spec
*/
public function __construct(SpecificationInterface $spec)
{
$this->spec = $spec;
}
/**
* 返回规格的相反结果
*
* @param Item $item
*
* @return bool
*/
public function isSatisfiedBy(Item $item)
{
return !$this->spec->isSatisfiedBy($item);
}
}

PriceSpecification.php

<?php
namespace DesignPatterns\Behavioral\Specification;

/**
* 判断给定Item的价格是否介于最小值和最大值之间的规格
*/
class PriceSpecification extends AbstractSpecification
{
protected $maxPrice;
protected $minPrice;
/**
* 设置最大值
*
* @param int $maxPrice
*/
public function setMaxPrice($maxPrice)
{
$this->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() < $this->minPrice) {
return false;
}
return true;
}
}

4、测试代码

Tests/SpecificationTest.php

<?php
namespace DesignPatterns\Behavioral\Specification\Tests;
use DesignPatterns\Behavioral\Specification\PriceSpecification;
use DesignPatterns\Behavioral\Specification\Item;
/**
* SpecificationTest 用于测试规格模式
*/
class SpecificationTest extends \PHPUnit_Framework_TestCase
{
public function testSimpleSpecification()
{
$item = new Item(100);
$spec = new PriceSpecification();
$this->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));
}
}

以上内容是三水点靠木小编给大家分享的PHP 设计模式系列之 specification规格模式,希望本文分享能够帮助大家。

PHP 相关文章推荐
用 php 编写的日历
Oct 09 PHP
php5数字型字符串加解密代码
Apr 24 PHP
自己在做项目过程中学到的PHP知识收集
Aug 20 PHP
学习php过程中的一些注意点的总结
Oct 25 PHP
PHP获取短链接跳转后的真实地址和响应头信息的方法
Jul 25 PHP
ThinkPHP中使用ajax接收json数据的方法
Dec 18 PHP
Laravel框架中实现使用阿里云ACE缓存服务
Feb 10 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
Dec 07 PHP
PHP设计模式之简单投诉页面实例
Feb 24 PHP
Yii框架中jquery表单验证插件用法示例
Oct 18 PHP
深入学习微信网址链接解封的防封原理visit_type
Aug 15 PHP
Laravel 自定命令以及生成文件的例子
Oct 23 PHP
PHP生成各种常见验证码和Ajax验证过程
Jan 10 #PHP
PHP常用字符串操作函数实例总结(trim、nl2br、addcslashes、uudecode、md5等)
Jan 09 #PHP
PHP统计目录中文件以及目录中目录大小的方法
Jan 09 #PHP
PHP基于单例模式实现的mysql类
Jan 09 #PHP
thinkPHP查询方式小结
Jan 09 #PHP
thinkPHP中多维数组的遍历方法
Jan 09 #PHP
ThinkPHP中html:list标签用法分析
Jan 09 #PHP
You might like
PHP命令行执行整合pathinfo模拟定时任务实例
2016/08/12 PHP
php利用header函数下载各种文件
2016/08/24 PHP
Laravel使用RabbitMQ的方法示例
2019/06/18 PHP
用javascript控制iframe滚动的代码
2007/04/10 Javascript
一段非常简单的js判断浏览器的内核
2014/08/17 Javascript
javascript 实现map集合
2015/04/03 Javascript
JavaScript实现为指定对象添加多个事件处理程序的方法
2015/04/17 Javascript
js实现n秒倒计时后才可以点击的效果
2015/12/20 Javascript
jQuery绑定事件的四种方式介绍
2016/10/31 Javascript
js自定义QQ菜单效果
2017/01/10 Javascript
JavaScript中数组Array方法详解
2017/02/27 Javascript
javascript使用btoa和atob来进行Base64转码和解码
2017/03/20 Javascript
Vue创建头部组件示例代码详解
2018/10/23 Javascript
Angular8 Http拦截器简单使用教程
2019/08/20 Javascript
Layui table field初始化加载时进行隐藏的方法
2019/09/19 Javascript
微信用户访问小程序的登录过程详解
2019/09/20 Javascript
JavaScript实现简单随机点名器
2019/11/21 Javascript
Python合并字符串的3种方法
2015/05/21 Python
使用python实现男神女神颜值打分系统(推荐)
2019/10/31 Python
Python3中configparser模块读写ini文件并解析配置的用法详解
2020/02/18 Python
Pycharm中安装Pygal并使用Pygal模拟掷骰子(推荐)
2020/04/08 Python
Django Form常用功能及代码示例
2020/10/13 Python
Matplotlib中rcParams使用方法
2021/01/05 Python
HTML5实现WebSocket协议原理浅析
2014/07/07 HTML / CSS
皮尔·卡丹巴西官方商店:Pierre Cardin
2017/07/21 全球购物
Crabtree & Evelyn英国官网:瑰珀翠护手霜、香水、沐浴和身体护理
2018/04/26 全球购物
印尼极简主义和实惠的在线家具店:Fabelio
2019/03/27 全球购物
《争吵》教学反思
2014/02/15 职场文书
传播学专业毕业生自荐书
2014/07/01 职场文书
2015年世界艾滋病日活动总结
2015/03/24 职场文书
2015民办小学年度工作总结
2015/05/26 职场文书
2015年中学总务处工作总结
2015/07/22 职场文书
使用golang编写一个并发工作队列
2021/05/08 Golang
python保存图片的四个常用方法
2022/02/28 Python
PyTorch中的torch.cat简单介绍
2022/03/17 Python
最新动漫情报:2022年7月新番定档超过30部, OVERLORD骨王第四季也在其中噢
2022/05/04 日漫