Specification Pattern

不了解 SOLID 的可以扫一眼这个:SOLID,面向对象设计五大基本原则。

今天扫 SOLID JS 的时候,授课者对 OCP 的一个实现方式利用了 Specification Pattern,所以这里也进行一下补充学习。

不过讲道理来说,因为 JavaScript 是一个弱类型的语言,所以很难强制让子类去实现其他语言中 interface/abstract 的函数,这也是一个局限了。

使用案例为,假设需要实现一个过滤器(filter),最初的实现方式如下:

const COLOR = Object.freeze({RED: 'red',GREEN: 'green',BLUE: 'blue',
});const SIZE = Object.freeze({SMALL: 'small',MEDIUM: 'medium',LARGE: 'large',
});class Product {constructor(name, color, size) {this.name = name;this.color = color;this.size = size;}
}class ProductFilter {filterByColor(products, color) {return products.filter((p) => p.color === color);}filterBySize(products, size) {return products.filter((p) => p.size === size);}
}const apple = new Product('Apple', COLOR.GREEN, SIZE.SMALL);
const tree = new Product('Tree', COLOR.GREEN, SIZE.LARGE);
const house = new Product('House', COLOR.BLUE, SIZE.LARGE);const products = [apple, tree, house];const pf = new ProductFilter();console.log('Green products:');
for (const p of pf.filterByColor(products, COLOR.GREEN)) {console.log(` * ${p.name} is green.`);
}

可以看到之后如果要写其他的 filter,也是可以继续在 ProductFilter 实现的,不过这里有几个问题:

  1. 继续实现其他的 filter 就要修改现有的代码
  2. 每一次新的需求来了,都需要额外实现新需求,这会引起 state space explosion 的问题,毕竟 3 个变量的 AND 操作,就需要 7 个方法去进行实现(A, B, C, A+B, B+C, A+C, A+B+C)。

一个解决这个问题的方法是使用 specification pattern,修改代码如下:

// should be done through inheritance, but js doesn't reenforce inheritance
// class Specification {}class ColorSpecification {constructor(color) {this.color = color;}isSatisfied(item) {return item.color === this.color;}
}class SizeSpecification {constructor(size) {this.size = size;}isSatisfied(item) {return item.size === this.size;}
}class FilterSpecs {filter(items, spec) {return items.filter((x) => spec.isSatisfied(x));}
}const fs = new FilterSpecs();console.log('Green products with specs:');
for (const p of fs.filter(products, new ColorSpecification(COLOR.GREEN))) {console.log(` * ${p.name} is green.`);
}

对于 AND 操作的实现补充如下:

class AndSpecifications {constructor(...specs) {this.specs = specs;}isSatisfied(item) {return this.specs.every((x) => x.isSatisfied(item));}
}console.log('Large and green products:');
const specs = new AndSpecifications(new ColorSpecification(COLOR.GREEN),new SizeSpecification(SIZE.LARGE)
);for (const p of fs.filter(products, specs)) {console.log(` * ${p.name} is green and large.`);
}

使用 specification pattern 的优势就在于极大地减少了函数的实现,原本对于 AND 的操作,3 个条件就需要实现 7 个方法,而后如果有更多的需求,就需要些更多的方法去满足这些需求,对于 n n n 个需求来说,就会有 n + n − 1 , + . . . + 1 n + n-1, + ... + 1 n+n−1,+...+1,也就是 n 2 n^2 n2 个方法。。使用了 specification pattern 现在只需要实现 3+1 个,并且如果之后有其他的需求了,在实现对应的基类后,只需要调用 AndSpecifications 并将对应的 specs 传进去就行,换言之,只需要实现 n + 1 n+1 n+1 个方法。

同样的,如果对 OR,XOR 操作也有需求,那么 specification pattern 就能省下大量的代码和开发时间。

Reference

  • Specification pattern

    wiki 上提供了不少的代码案例,包括 C#,Python,C++和 TS。

规格模式 Specification Pattern相关推荐

  1. php 规格,PHP 设计模式系列之 specification规格模式_PHP

    Plus.php left = $left; $this->right = $right; } /** * 返回两种规格的逻辑与评估 * * @param Item $item * * @ret ...

  2. 【设计模式】【27】规格模式

    应用场景 规格模式,英文名Specification Pattern 该模式将对产品特征的判断标准封装成规格类,专门用来判断产品是否合格 这种设计模式主要用于结果判断类的业务,比如我们做单元测试时,有 ...

  3. 频繁模式(frequent pattern)

    Datawhale 频繁模式(frequent pattern) 频繁模式一般是指频繁地出现在数据集中的模式.这种频繁模式和关联规则是数据挖掘中想要挖掘的知识. 我们都知道一个很有趣的故事,就是啤酒和 ...

  4. 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern)

    [索引页] [源码下载] 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) 作者:webabcd 介绍 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互 ...

  5. 8.6 GOF设计模式四: 策略模式… Strategy Pattern

    策略模式- Strategy Pattern  在POS系统中,有时需要实行价格优惠, 该如何处理?  对普通客户或新客户报全价  对老客户统一折扣5%  对大客户统一折扣10%  注:课件 ...

  6. 设计模式(十二):通过ATM取款机来认识“状态模式”(State Pattern)

    说到状态模式,如果你看过之前发布的重构系列的文章中的<代码重构(六):代码重构完整案例>这篇博客的话,那么你应该对"状态模式"并不陌生,因为我们之前使用到了状态模式进行 ...

  7. 设计模式 - 迭代器模式(iterator pattern) 具体解释

    迭代器模式(iterator pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 迭代器模式(iterator pattern) : 提供一 ...

  8. 设计模式:迭代器模式(Iterator Pattern)

    迭代器模式(Iterator Pattern): 属于行为型模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即: 不暴露其内部结构.

  9. 设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern): 封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 主要将数据结构与数据操作分离,解决数据结构和操作 ...

最新文章

  1. php blocklog_SQLSERVER中的logblock校验(译)
  2. python是用c写的吗-Python是编写人工智能最佳的编程语言吗?
  3. 于ubuntu配置hadoop当问题
  4. TensorRT(6)-INT8 inference
  5. 某考试 T1 monopoly
  6. 开发中常用的19 条 MySQL 优化技巧
  7. 我在华为做Android外包的真实经历!吊打面试官系列!
  8. Matlab样条拟合曲面,样条曲面拟合及其Matlab实现
  9. 程序员35岁辞职后都做了什么工作三位过来人透露了实情,引热议
  10. 用spss做哑变量--给不敲代码同学福音
  11. tensorflow函数介绍(3)
  12. lammps数据后处理:Python Ovito CNA结构统计输出
  13. DarkNet yoloV2 转到caffe使用
  14. 鬼迷心窍 歌词翻译 中译日
  15. QlikView 学习资料
  16. 蜜蜂CNN模糊进化深度学习算法
  17. 帆软报表文件上传、下载及删除功能
  18. AI 黑科技,老照片修复,模糊变高清
  19. 最新最全的免费股票数据接口--沪深A股深度分析机构持股数据API接口(十二)
  20. 谈谈阿里云弹性公网IP

热门文章

  1. mysql实操《学生表》
  2. 前端开发者如何用JS开发后台
  3. RAID详解+RAID5配置实战
  4. c语言程序设计 大学考试题库,广东工业大学《C语言程序设计》考试复习重点题库.pdf...
  5. 小杜机器人线下店_小度首家官方体验店开业啦!线下体验小度系列产品 智能家居任你玩...
  6. 原生js与jQuery显示隐藏div的几种方法
  7. wpf 悬浮窗口的实现
  8. python字符串常用方法变量名命名规范
  9. 实现GB28181平台级联到海康平台的级联
  10. input的type属性整理