开放封闭原则:
开发过程中,因为变化、升级和维护等原因需要对原有逻辑进行修改时,很有可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有功能新测试。
我们应该尽量通过扩展实体的行为来实现变化,而不是通过修改已有的代码来实现变化
具体一点呢 —— 类、模块和函数应该对扩展开放,对修改关闭。模块应该尽量在不修改原代码的情况下进行扩展。
核心 —— 用抽象构建框架,用实现扩展细节。
总结一下 —— 开发人员应该对程序中呈现的频繁变化的那些部分作出抽象,然后从抽象派生的实现类来进行扩展,当代码发生变化时,只需要根据需求重新开发一个实现类来就可以了。要求我们对需求的变更有一定的前瞻性和预见性,同时拒绝对于应用程序中的每个部分都刻意的进行抽象。
设计模式6大原则:
单一原则 (SRP): 实现类要职责单一, 一个类只做一件事或者一类事,不要将功能无法划分为一类的揉到一起
里氏替换原则(LSP): 不要破坏继承体系,子类可以完全替换掉他们所继承的父类,可以理解为调用父类方法的地方换成子类也可以正常执行调用
依赖倒置原则(DIP): 如果某套功能或者业务逻辑可能之后会出现并行的另外一种模式或者较大的调整,那不如把这部分逻辑抽象出来,创建一个包含相关方法的抽象类,而实现类继承这个抽象类来重写抽象类中的方法,完成具体的实现,调用这些功能方法的类不需要关心自己调用的这些个方法的具体实现,只管调用这些抽象类中定义好的形式上的方法即可,不与实际实现这些方法的类发生直接依赖关系,方便之后的实现逻辑的替换更改;
接口隔离原则(ISP) : 在设计抽象类的时候要精简单一, 白话说就是,A需要依赖B提供的一些方法,A我只用B的3个方法,B就尽量不要给A用不到的方法啦;
迪米特法则(LoD) :降低耦合, 尽量减少对象之间的直接的交互,如果其中一个类需要调用另一个类的某一个方法的话,可通过一个关系类发起这个调用,这样一个模块修改时,就可以最大程度的减少波及。
开放-封闭原则(OCP) :告诉我们要对扩展开放,对修改关闭,你可以继承扩展我所有的能力,但是别动我本人
状态模式:
允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类。
用ts手写一个简单的状态模式:
//把每一个状态分支(一个状态对应的行为)放进一个独立的类中
const Actions = {
todo1: function () {
console.log('todo1');
},
todo2: function () {
console.log('todo2');
},
todo3: function () {
console.log('todo3');
}
};
class StateMachine {
//当前待执行的状态序列
private _currentState = [];
constructor() {
this._currentState = [];
}
//改变内部状态的接口
public changeState(stateList: string[]): StateMachine {
this._currentState = [];
for (let state of stateList) {
this._currentState.push(state);
}
return this;
}
//实现内部状态分支的接口
public runState(): void {
for (let state of this._currentState) {
Actions[state] && Actions[state].apply(this);
}
}
}
//test
let obj = new StateMachine();
obj.changeState(['todo1', 'todo2']).runState();//通知执行'todo1', 'todo2'两种状态
状态模式的优缺点
优点:一个状态对应的行为作为一个方法封装在一个类里,直观清晰,互相独立,不用写很多的if else
缺点:需要考虑状态行为分支拆分的程度 避免过度设计反而降低代码可读性
状态模式的一个模型-有限状态机
github上有一个有限状态机的函数库javascript-state-machine
https://github.com/jakesgordon/javascript-state-machine
ts代码示例:实现一个有限状态机:
import * as StateMachine from 'javascript-state-machine';
let _fsm = StateMachine.create({
//红绿灯状态机的初始状态
initial: 'green',
//触发状态改变的各种事件,比如greenToYellow事件使green状态变成yellow状态
events: [
{ name: 'greenToYellow', from: 'green', to: 'yellow' },
{ name: 'yellowToRed', from: 'yellow', to: 'red' },
{ name: 'redToYellow', from: 'red', to: 'yellow' },
{ name: 'yellowToGreen', from: 'yellow', to: 'green' }
],
//js-state-machine可以为每个事件指定两个回调函数 onbeforexxx在xxx事件发生前触发 onafterxxx|onxxx在xxx事件发生后触发
//js-state-machine可以为每个状态指定两个回调函数 onleavexxx在离开xxx状态时触发 onenterxxx在进入xxx状态时触发
callbacks: {
//以greenToYellow事件为例
onbeforegreenToYellow: () => {
console.log('greenToYellow 准备触发');
},
onaftergreenToYellow: () => {
console.log('greenToYellow 触发了');
},
//以green状态为例
onleavegreen: () => {
console.log('离开green状态');
},
onentergreen: () => {
console.log('进入green状态');
},
//除了为每个事件和状态单独指定回调函数 还可以为所有的事件和状态指定通用的回调函数
onbeforeevent: () => {
// console.log('任一事件发生前触发');
},
onafterevent: () => {
// console.log('任一事件结束后触发');
},
onleavestate: () => {
// console.log('任一状态离开时触发');
},
onenterstate: () => {
// console.log('任一状态进入时触发');
},
error: function (eventName, from, to, args, errorCode, errorMessage) {
console.log('event ' + eventName + ': ' + errorMessage);
}
}
});
console.log('_fsm.current=' + _fsm.current);//green
//a.同步状态改变
// _fsm.greenToYellow();
// console.log('_fsm.current=' + _fsm.current);//green
//b.如果希望在离开green状态时先完成异步操作再离开 可以使用transition方法
_fsm.onleavegreen = function () {
setTimeout(() => {
_fsm.transition();
console.log('_fsm.current after setTimeout=' + _fsm.current);//yellow
}, 1000);
return StateMachine.ASYNC;
};
_fsm.greenToYellow();
console.log('_fsm.current=' + _fsm.current);//green
// _fsm.redToYellow();//直接调用会报错 因为当前状态不是red 那如何判断呢?可以用下面的查询方法
console.log(_fsm.is('red'));//返回状态机当前状态是不是'red'
console.log(_fsm.can('redToYellow'));//返回'redToYellow'这个事件能否在当前状态下执行