## 定义
       规格模式是组合模式的一种扩展。这是一种结构型设计模式。
       通过条件关系（与、或、非）组合，来处理查询或过滤，而不是使用逻辑判断语句来处理，可以使逻辑更加简单。这里的每个条件都是一个规格，多个规格串联形成一个组合式的规格。


## 设计的原则和思想
1. 解耦的是业务逻辑和逻辑条件。
2. 不变部分是逻辑条件，变化部分是业务逻辑。
3. 核心思想是通过逻辑运算的方式简化和定制业务逻辑。


## 一句话概括设计模式
    组合模式(逻辑规格书和整体规格书的关系就是局部和整体的关系) + 策略模式(一个规则书是一个策略)。

## 结构中包含的角色
1. Specification 抽象规格书
2. CompositeSpecification 组合规格书
3. AndSpecification 逻辑条件“与”规划书
4. BizSpecification 业务规格书

## 最小可表达代码
    // 抽象规格书
    interface Specification {
        public function isSatisfiedBy($candidate);
        public function and(Specification $spec);
    }

    // 组合规格书
    abstract class CompositeSpecification implements Specification
    {
        public function and(Specification $spec)
        {
            return new AndSpecification($this, $spec);
        }
    }

    // 与规划书
    class AndSpecification extends CompositeSpecification
    {
        private $left;
        private $right;
    
        public function __construct(Specification $left, Specification $right)
        {
            $this->left = $left;
            $this->right = $right;
        }
    
        public function isSatisfiedBy($candidate)
        {
            return $this->left->isSatisfiedBy($candidate) && $this->right->isSatisfiedBy($candidate);
        }
    }

    // 年龄规划书(BizSpecification)
    class AgeSpecification extends CompositeSpecification
    {
        public function isSatisfiedBy($student)
        {
            return $student['age'] > 18;
        }
    }

    // 性别规划书(BizSpecification)
    class SexSpecification extends CompositeSpecification
    {
        public function isSatisfiedBy($student)
        {
            return $student['sex'] == '女';
        }
    }

    $students = [
        ['name' => '张3','age' => 18, 'sex' => '男'],
        ['name' => '张4','age' => 20, 'sex' => '女'],
        ['name' => '张5','age' => 20, 'sex' => '男'],
    ];
    $ageSpecification = new AgeSpecification();
    $sexSpecification = new SexSpecification();
    $studentSpecification = $ageSpecification->and($sexSpecification);
    $data = [];
    foreach ($students as $student) {
        if ($studentSpecification->isSatisfiedBy($student)) {
            $data[] = $student;
        }
    }
    var_dump($data);

## 何时使用
1. 筛选数据。
2. 查询数据。


## 实际应用场景
1. 数据过滤。
2. 数据库SQL条件组合。
