这是我参与 8 月更文挑战的第 11 天,活动详情查看: 8月更文挑战
前言
命令模式(Command Pattern)
用于将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及执行可撤销的操作。也就是说改模式旨在将函数的调用、请求和操作封装成一个单一的对象。
function Command(execute, undo, value) {
this.execute = execute;
this.undo = undo;
this.value = value;
}
var AddCommand = function (value) {
return new Command(add, sub, value);
};
var SubCommand = function (value) {
return new Command(sub, add, value);
};
var MulCommand = function (value) {
return new Command(mul, div, value);
};
var DivCommand = function (value) {
return new Command(div, mul, value);
};
命令具有以下的优点:
(1)命令模式使新的命令很容易地被加入到系统里。
(2)允许接收请求的一方决定是否要否决请求。
(3)能较容易地设计一个命令队列。
(4)可以容易地实现对请求的撤销和恢复。
(5)在需要的情况下,可以较容易地将命令记入日志。
解释器模式(Interpreter Pattern)
解释器模式用于构造一个简单的语言解释器,将字符串按照自定义的方式解释执行 ,是一种不常用的设计模式。除非从事底层开发自己需要去定义较为复杂的表达式,否则基本上不同这个设计模式,而且像很多语言其实都有提供动态代码的执行或者VM的功能。
比如实现一个对字符串判断是否是偶数
function Interpreter(str) {
return Number(str) % 2 !== 0;
}
优点:
- 易于扩展和修改文法规则。增加时只需要增加新的终结符表达式,符合开关原则。
缺点:
- 对于复杂文法难以维护,会充满非终结表达式。
- 执行效率低,由于使用了大量循环和递归调用,在解释复杂句子时速度很慢。
迭代器模式(Iterator Pattern)
基本上是每种语言都会实现的一种模式,提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
function each(arr, fn) {
for (let item of arr) {
fn(item)
}
}
each([1, 2, 3], function(item) {
console.log(item)
})
中介者模式(Mediator Pattern)
中介者模式主要用于一个系统中存在大量的对象,而且这些大量的对象需要互相通信,因为两个对象需要通信,一个对象必须要持有另一个对象,这样就会导致,系统里,每个对象都互相引用,会引起混乱,中介者把所有的对象都统一管理起来,其他的对象通过中介者去和别的对象通信。
我们可以大致看下Vue的实现
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
const vm: Component = this
/*如果是数组的时候,则递归$on,为每一个成员都绑定上方法*/
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.$on(event[i], fn)
}
} else {
(vm._events[event] || (vm._events[event] = [])).push(fn)
// optimize hook:event cost by using a boolean flag marked at registration
// instead of a hash lookup
/*这里在注册事件的时候标记bool值也就是个标志位来表明存在钩子,而不需要通过哈希表的方法来查找是否有钩子,这样做可以减少不必要的开销,优化性能。*/
if (hookRE.test(event)) {
vm._hasHookEvent = true
}
}
return vm
}
Vue.prototype.$emit = function (event: string): Component {
const vm: Component = this
if (process.env.NODE_ENV !== 'production') {
const lowerCaseEvent = event.toLowerCase()
if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
tip(
`Event "${lowerCaseEvent}" is emitted in component ` +
`${formatComponentName(vm)} but the handler is registered for "${event}". ` +
`Note that HTML attributes are case-insensitive and you cannot use ` +
`v-on to listen to camelCase events when using in-DOM templates. ` +
`You should probably use "${hyphenate(event)}" instead of "${event}".`
)
}
}
let cbs = vm._events[event]
if (cbs) {
/*将类数组的对象转换成数组*/
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
/*遍历执行*/
for (let i = 0, l = cbs.length; i < l; i++) {
cbs[i].apply(vm, args)
}
}
return vm
}
备忘录模式(Memento Pattern)
备忘录设计模式非常的适合在缓存还原的场景,就是我把某个状态数据先做缓存,存于内存或者其他的媒介中,在切换回来此状态时直接到缓存中的状态数据给导出,不需要再一步步的进行new操作,提高对象实体生成的效率,提高工作效率和场景体验。
比如,实现一个斐波那契数列的求和
function fn(n) {
if (n < 2) {
return n;
}
return fn(n - 1) + fn(n - 2)
}
当我们把n稍调大的时候,就可以发现速度特别慢,甚至会爆栈。原因是中间存在了大量的重复计算,我们来通过备忘录模式做一波优化。
const memento = {};
function fn(n) {
if (n < 2) {
return n;
}
if (memento[n]) {
return memento[n]
}
memento[n] = fn(n - 1) + fn(n - 2)
return memento[n]
}
最后打波小广告,美团校招社招内推,不限部门,不限岗位,不限投递数量,海量hc,快来快来~