Appearance
创建性设计模式
工厂模式
用于创建实例,就像工厂一样,输出参数,得到实例结果。包含工厂和实例类两个核心概念。工厂类的产出都应该是相识,或者叫一类东西(注意这个概念)
js
// 实例类
function One() {
this.content = 'one'
}
function Two() {
this.content = 'two'
}
function Three() {
this.content = 'three'
}
function createFactory(type) { // 工厂
switch(type) {
case 'one':
return new One()
case 'two':
return new Two()
case 'three':
return new Three()
}
}
// 或者类的方式
function CreateFactory(type) { // 工厂
switch(type) {
case 'one':
return new One()
case 'two':
return new Two()
case 'three':
return new Three()
}
}
const some = createFactory('two') // 工厂创建实例工厂方法模式
如果要新增一个Four类,工厂方法类需要新增一个类和修改工厂方法,而且有可能使用者不清楚createFactory 到底是一个类还是方法。需要引入安全类模式(见代码)。
工厂方法是指将类的创建过程流转到子类中执行,核心类就变成了抽象类,同时引入安全类模式。好处是新增类时只用改一个地方
js
CreateFactory.set = {
One() {
this.content = 'one'
},
Two() {
this.content = 'two'
},
Three() {
this.content = 'three'
}
}
function CreateFactory(type) { // 安全类实现
if(this instanceOf CreateFactory) {
return new CreateFactory.set[type]() // new如果返回一个对象,将对象作为实例,如果返回undefined,当前的this作为实例
} else {
return new CreateFactory(type)
}
}抽象工厂模式
工厂模式用于创建示例,抽象工厂用于创建类。包含工厂类,工厂中的抽象类,产品类三个部分。 比如培训制造汽车的厂,这个厂可以培训出其他汽车厂,其他汽车厂可以造汽车,这样别人只要知道是某个培训厂出来的就知道车有什么特性。
总的来说就是通过工厂模式创建了抽象类,不是具体的产品。真正的产品都是这些抽象类的实现。
js
class AbstractFactory {
constructor(subClass, type) {
if(new.target === AbstractFactory) {
throw new Error('抽象类不能实例化')
}
// 将某个产品的特性交给某个来学习的厂
function F() {}
F.prototype = new AbstractFactory.set[type]();
subClass.prototype = new F();
return subClass
}
// 保存了这个厂所有抽象类
static set = {
Car: class Car {
constructor() {
this.model = 'car'
}
featureA() {
throw new Error('制造car需要自行完成特性A')
}
featureB() {
throw new Error('制造car需要自行完成特性B')
}
},
Bus: class Bus {
constructor() {
this.model = 'Bus'
}
featureA() {
throw new Error('制造Bus需要自行完成特性A')
}
featureB() {
throw new Error('制造Bus需要自行完成特性B')
}
},
Truck: class Truck {
constructor() {
this.model = 'Truck'
}
featureA() {
throw new Error('制造Truck需要自行完成特性A')
}
featureB() {
throw new Error('制造Truck需要自行完成特性B')
}
}
}
}
// 现在有一家宝马厂,最开始不会造汽车,但是有一些基础的技术BMWBase,想学习造汽车
class BMWBase { }
const BMWCar = new AbstractFactory(BMWBase, 'Car');
const bmwCar = new BMWCar()建造者模式
在创建一个实例过程中,对实例每个特性都使用单独实例来创建。
js
class Sex {
constructor(sex) {
this.sex =
}
}
class Age {
constructor(age) {
this.age = age
}
}
class Name {
constructor(name) {
this.name = name;
}
}
// 根据几个特性创建学生
class Student {
constructor(name, age, sex) {
if(name instanceOf Name || age instanceOf Age || sex instanceOf Sex ) {
throw new Error('具体化实例')
}
this._name = name;
this._age = age;
this._sex= sex;
}
}单例模式
保证某个类只有唯一的实例,多次创建也只返回相同的实例
js
function Human(name) {
if(Human._cache) {
return Human._cache;
}
this.name = name;
Human._cache = this;
}
const p1 = new Human('a')
const p2 = new Human('b')
console.log(p1 === p2)上面的方式将实例缓存到类的静态属性上,也可能出现修改的场景,通过闭包的方式避免修改。
js
function Human(name) {
this.name = name;
}
const createSingleInstanceClass = function(targetClass) {
return (function() {
let _cache
return function(...args) {
if(!_cache) {
_cache = new targetClass(...args)
}
return _cache
}
})()
}
const HumanSingle = createSingleInstanceClass(Human)
const p1 = new HumanSingle('a')
const p2 = new HumanSingle('b')
console.log(p1 === p2)结构性设计模式
外观模式
将复杂的子系统接口创建成高级的封装好的接口
适配器模式
将不同接口统一化,降低使用成本。前提是不同接口描述的功能是一类
代理模式
通过一个新的对象完全代理对就对象的操作,代理模式的核心是代理对象和被代理的对象保持接口的一致,当删除代理对象时,程序的基本功能正常。
js
class MyImage {
constructor() {
this.img = document.createElement('img')
document.appendChild(img)
}
setSrc(src) {
this.img.src = src
}
}
function createImageProxy() {
return class ProxyMyImage {
constructor(src) {
this.image = new Image
this.myImage = new MyImage()
this.image.onload = () => {
myImage.setSrc(image)
}
}
setSrc(src) {
this.myImage.setSrc('default.jpg')
this.image.src = src
}
}
}js
// 实现一个代理请求的接口
function uploadFile(file) {
console.log(file)
}
const uploadFileProxy = (function() {
let cache = [];
let timer = null;
return function(id) {
cache.push(id)
if(!timer) {
timer = setTimeout(() => {
cache.forEach(file => upload(file))
time = null;
cache = [];
}, 2000)
}
}
})()
uploadFileProxy('some')
uploadFile('some') // 在接口使用上没有差别,当以后代理类不需要时,可以放心的替换组合模式
包含抽象base类,container容器类(基于base),元素类(基于base),每个类可以嵌套其他类(item类不行),每个类有统一的接口。
享元模式
将一个类区分为内部状态和外部状态,内部状态是指多个对象都是相同,用于共享。外部状态是变化的,当需要一个对象,将内部状态和外部状态组合。本质上是时间换空间的操作。
行为性设计模式
模版模式
实现一个抽象父类,并定义执行的流程,子类依次实现步骤
js
class Base {
constructor() {
this.actionA();
this.actionB();
this.actionC();
}
actionA() {
throw new Error('action A should define by sub')
}
actionB() {
throw new Error('action B should define by sub')
}
actionC() {
throw new Error('action C should define by sub')
}
}
class Action extend Base {
actionA() {} // 依次重写
actionB() {}
actionC() {}
}观察者模式
分为被观察者和观察对象、也有衍生出发布订阅模式。
js
class Watcher {
// 观察一个对象
watch(good) {
good._watcher.push(this)
}
// 观察者回调
run() {
console.log('商品变少,接收到通知')
}
}
class Good {
_watchers = [];
count = 10
out() {
this.count--;
// 通知所有的watcher
this._watchers.forEach(watcher => {
watcher.run(this.count)
})
}
}
const watcher = new Watcher();
const good = new Good();
watcher.watch(good); // 观察
good.out();发布订阅和观察者模式区别是对于依赖的管理,观察者模式的依赖是被观察对象本身在管理(如果依赖管理稍微复杂,被观察对象本身也会变复杂),会带来一些和被观察对象无关的状态。发布订阅是将依赖的管理交给订阅中心,结构上更去耦合。
js
class Watcher {
center = center
// 观察一个对象
watch() {
this.center.sub(this)
}
// 观察者回调
run() {
console.log('商品变少,接收到通知')
}
}
const center = (() => {
const _watcher = [];
return {
sub(watcher) {
_watcher.push(watcher)
},
publish(data) {
_watcher.forEach(watcher => watcher.run(data))
}
}
})()
class Good {
center = center;
count = 10
out() {
this.count--;
// 通知所有的watcher
this.center.publish(this.count)
}
}
const watcher = new Watcher();
const good = new Good();
watcher.watch(); // 观察
good.out();命令模式
将接受者总是封装成命令类,请求总是和命令绑定从而执行命令,忽略接受者的差异。 命令核心就是命令类,接受者和请求者,请求者总是会执行命令类,命令类将请求转发给未来的接受者。
ts
abstract class BaseCommand {
abstract execute() {}
}
class OrderCommand extends BaseCommand {
constructor(receiver) {
this.receiver = receiver
}
executed() {
this.receiver();
}
}
abstract class BaseAction {
abstract command
abstract addCommand() {}
abstract action() {}
}
class MoveAction extends BaseAction {
command = null
addCommand(command) {
this.command = command;
}
action() {
this.command.execute();
}
}责任链模式
责任链模式是将一个大函数拆分成参数功能相似的区段。数据在区段之前流转,上一个处理函数不满足,流转到下一条,如果满足,责任链终止。就需要满足责任链的处理函数总是能满足当前函数所有的功能。 包含处理函数、责任链节点两个关键类。
ts
/**
* 订单超过500的,打7折,
* 订单在200~500之间,如果level是A,打8折,如果level是B,打8.5折。
* 如果订单在200以下,并且有card,打9折,没有card原价。
*/
function originFn(order, level, hasCard) {
if(order > 500) {
return order * 0.7
}
else if () {}
else if () {} // 如果if else,新增修改规则变麻烦
....
}
// 按照打折的维度拆分,固定参数为 order, level, hasCard
function order500(order) {
return order * 0.7
}
function order200500(order, level) {
if(level === A) {
return order * 0.8
} else {
return order * 0.85
}
}
function orderLess200(order, _, hasCard) {
return order * 0.9
}
function orderNormal(order) {
return order
}
abstract class ChainAbstract {
fn
nextChain
abstract setNextChain() {}
abstract startCurrentChain() {}
}
class Chain extends ChainAbstract {
nextChain = null
constructor(fn) {
this.fn = fn;
}
setNextChain(chain) {
this.nextChain = chain;
}
startCurrentChain(...args) {
let ret = this.fn(...args)
if(ret === 'next') {
return this.nextChain && this.nextChain.startCurrentChain(...args)
}
return ret
}
startChainAsync(cb, ...args) {
this.fn((ret) => {
if(ret === 'next') {
return this.nextChain && this.nextChain.startCurrentChain(cb, ...args)
}
return cb(ret)
}, ...args)
}
}
const chain500 = new Chain(order500)
const chain200500 = new Chain(order200500)
const chainLess200 = new Chain(orderLess200)
chain500.setNextChain(chain200500)
chain200500.setNextChain(chainLess200)
chain500.startCurrentChain(700, 'A', false)中介模式
节点本身不做逻辑处理,将状态上传到中介方,又中介调度处理。这样节点不用关注其他节点,尽可能少的额外状态。
状态机模式
实体类、状态类,状态切换函数。
ts
abstract class LightStateAbstract {
light: Light
constructor(light) {
this.light = light
}
abstract pressButton
}
class OnLightState extends LightStateAbstract {
pressButton() {
console.log('current is on, next is off')
this.light.setState(this.light.off)
}
}
class OffLightState extends LightStateAbstract {
pressButton() {
console.log('current is off, next is on')
this.light.setState(this.light.on)
}
}
class Light {
constructor() {
this.on = new OnLightState(this);
this.off = new OffLightState(this);
this.currentState = this.on;
}
setState(state: LightState) {
this.currentState = state;
}
pressButton() {
this.currentState.pressButton();
}
}
const light = new Light();
light.pressButton(); // on
light.pressButton(); // off
light.pressButton(); // onjs中有基于FSM的状态机。实现逻辑差不多。
ts
const FSM = {
on: {
press() {
console.log('on')
this.currentState = this.off;
}
},
off: {
press() {
console.log('off')
this.currentState = this.on
}
}
}
const light = {
on: FSM.on,
off: FSM.off,
currentState: FSM.,
press() {
this.currentState.press.call(this)
}
}基于闭包的状态机。上面状态都是手动声明,通过闭包来保存当前的状态
ts
function delegate(light, next) {
return {
press() {
}
}
}