1.单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
var Singleton = function (name) {
this.name = name;
this.instance = null;
};
Singleton.prototype.getName = function () {
console.log(this.name);
};
Singleton.getInstance = function (name) {
if (!this.instance) {
this.instance = new Singleton(name);
}
return this.instance;
};
var a = Singleton.getInstance( 'sven1' );
var b = Singleton.getInstance( 'sven2' );
console.log( a === b ); // true
// 或者
var Singleton = function (name) {
this.name = name;
};
Singleton.prototype.getName = function () {
console.log(this.name);
};
Singleton.getInstance = (function () {
var instance = null;
return function (name) {
if (!instance) {
instance = new Singleton(name);
}
return instance;
}
})();
2.策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
例如代码实现:绩效为 S 的人年 终奖有 4 倍工资,绩效为 A 的人年终奖有 3 倍工资,而绩效为 B 的人年终奖是 2 倍工资。假设财 务部要求我们提供一段代码,来方便他们计算员工的年终奖
。
- 最初的代码实现
var calculateSalary = function (performance, salary) {
var num = 1;
switch (performance) {
case 'S':
num = 4;
break;
case 'A':
num = 3;
break;
case 'B':
num = 2;
break;
}
return salary * num;
}
- 策略模式重构代码
-
其的目的就是将算法的使用与算法的实现分离开来。
image.png
-
模仿传统面向对象语言中的实现
// 1.封装绩效规则
var performanceS = function () { };
performanceS.prototype.calculate = function (salary) {
return salary * 4;
};
var performanceA = function () { };
performanceA.prototype.calculate = function (salary) {
return salary * 3;
};
var performanceB = function () { };
performanceB.prototype.calculate = function (salary) {
return salary * 2;
};
// 2.定义奖金类 Bonus:
var Bonus = function () {
this.salary = null; // 原始工资
this.strategy = null; // 绩效等级对应的策略对象
};
Bonus.prototype.setSalary = function (salary) {
this.salary = salary; // 设置员工的原始工资
};
Bonus.prototype.setStrategy = function (strategy) {
this.strategy = strategy; // 设置员工绩效等级对应的策略对象
};
Bonus.prototype.getBonus = function () { // 取得奖金数额
return this.strategy.calculate(this.salary); // 把计算奖金的操作委托给对应的策略对象
}
// 算法的使用
var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new performanceS()); // 设置策略对象
console.log(bonus.getBonus()); // 输出:40000
bonus.setStrategy(new performanceA()); // 设置策略对象
console.log(bonus.getBonus()); // 输出:30000
JavaScript 版本的策略模式:
var strategies = {
'S': function (salary) {
return salary * 4;
},
'A': function (salary) {
return salary * 3;
},
'B': function (salary) {
return salary * 2;
}
};
var calculateBonus = function (level, salary) {
return strategies[level](salary);
};
console.log(calculateBonus('S', 20000)); // 输出:80000
console.log(calculateBonus('A', 10000)); // 输出:30000
- 发布—订阅模式
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<input type="text" name="userName"/>
<p></p>
<script>
var inp = document.querySelector('input');
var p = document.querySelector('p');
// 发布订阅对象
var obj = {};
// 发布订阅事件列表
obj.list = {}
// 定义订阅事件函数
obj.listen = function (eventName, fn) {
obj.list[eventName] = fn;
}
// 定义发布事件函数
obj.trigger = function (eventName) {
obj.list[eventName]();
}
// 数据
var data = {str:'hello'}
var str = data.str;
// 观察数据变动从而触发所订阅事件
Object.defineProperty(data, 'str', {
get () {
return str;
},
set (newVal) {
str = newVal;
console.log(data.str, data);
obj.trigger('go')
}
})
// 订阅一个事件
obj.listen('go', function () {
p.innerText = data.str;
inp.value = data.str;
})
// 数据变动
inp.oninput = function () {
data.str = this.value;
}
</script>
</body>
</html>
- 模板方法模式
模板方法模式是一种只需使用继承就可以实现的非常简单的模式.
是基于继承的一种设计模式,父类封装了子类的算法框架和方法的执行顺序,
子类继承父类之后,父类通知子类执行这些方法。
例子:
var Beverage = function () { };
Beverage.prototype.boilWater = function () {
console.log('把水煮沸');
};
Beverage.prototype.brew = function () {
throw new Error('子类必须重写 brew 方法');
};
Beverage.prototype.pourInCup = function () {
throw new Error('子类必须重写 pourInCup 方法');
};
Beverage.prototype.addCondiments = function () {
throw new Error('子类必须重写 addCondiments 方法');
};
Beverage.prototype.customerWantsCondiments = function () {
return true; // 默认需要调料
};
Beverage.prototype.init = function () {
this.boilWater();
this.brew();
this.pourInCup();
if (this.customerWantsCondiments()) { // 如果挂钩返回 true,则需要调料
this.addCondiments();
}
};
var CoffeeWithHook = function () { };
CoffeeWithHook.prototype = new Beverage();
CoffeeWithHook.prototype.brew = function () {
console.log('用沸水冲泡咖啡');
};
CoffeeWithHook.prototype.pourInCup = function () {
console.log('把咖啡倒进杯子');
};
CoffeeWithHook.prototype.addCondiments = function () {
console.log('加糖和牛奶');
};
CoffeeWithHook.prototype.customerWantsCondiments = function () {
return window.confirm('请问需要调料吗?');
};
var coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.init();
- 职责链模式
假设我们负责一个售卖手机的电商网站,经过分别交纳 500 元定金和 200 元定金的两轮预定后(订单已在此时生成),现在已经到了正式购买的阶段。公司针对支付过定金的用户有一定的优惠政策。在正式购买后,已经支付过500 元定金的用户会收到 100 元的商城优惠券,200 元定金的用户可以收到 50 元的优惠券,而之前没有支付定金的用户只能进入普通购买模式,也就是没有优惠券,且在库存有限的情况下不一定保证能买到。
初步实现:
var order = function (orderType, pay, stock) {
if (orderType === 1) { // 500 元定金购买模式
if (pay === true) { // 已支付定金
console.log('500 元定金预购, 得到 100 优惠券');
} else { // 未支付定金,降级到普通购买模式
if (stock > 0) { // 用于普通购买的手机还有库存
console.log('普通购买, 无优惠券');
} else {
console.log('手机库存不足');
}
}
} else if (orderType === 2) { // 200 元定金购买模式
if (pay === true) {
console.log('200 元定金预购, 得到 50 优惠券');
} else {
if (stock > 0) {
console.log('普通购买, 无优惠券');
} else {
console.log('手机库存不足');
}
}
} else if (orderType === 3) {
if (stock > 0) {
console.log('普通购买, 无优惠券');
} else {
console.log('手机库存不足');
}
}
};
order(1, true, 500);// 输出: 500 元定金预购, 得到 100 优惠券
职责链模式代码重构:
var order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('500 元定金预购,得到 100 优惠券');
} else {
return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
var order200 = function (orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('200 元定金预购,得到 50 优惠券');
} else {
return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
var orderNormal = function (orderType, pay, stock) {
if (stock > 0) {
console.log('普通购买,无优惠券');
} else {
console.log('手机库存不足');
}
};
// 把函数包装进职责链节点
var Chain = function (fn) {
this.fn = fn;
this.successor = null;
};
Chain.prototype.setNextSuccessor = function (successor) {
return this.successor = successor;
};
Chain.prototype.passRequest = function () {
var ret = this.fn.apply(this, arguments);
if (ret === 'nextSuccessor') {
return this.successor && this.successor.passRequest.apply(this.successor, arguments);
}
return ret;
};
// 把 3 个订单函数分别包装成职责链的节点:
var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);
// 指定节点在职责链中的顺序:
chainOrder500.setNextSuccessor(chainOrder200);
chainOrder200.setNextSuccessor(chainOrderNormal);
// 把请求传递给第一个节点:
chainOrder500.passRequest(1, true, 500); // 输出:500 元定金预购,得到 100 优惠券
chainOrder500.passRequest(2, true, 500); // 输出:200 元定金预购,得到 50 优惠券
chainOrder500.passRequest(3, true, 500); // 输出:普通购买,无优惠券
chainOrder500.passRequest(1, false, 0); // 输出:手机库存不足
优点:
- 使用了职责链模式之后,链中的节点对象可以灵活地拆分重组,增加或者删除一个节点,或者改变节点在链中的位置都是轻而易举的事情
- 可以手动指定起始节点,请求并不是非得从链中的第一个节点开始传递
缺点:
- 不能保证某个请求一定会被链中的节点处理
- 职责链模式使得程序中多了一些节点对象,可能在某一次的请求传递过程中,大部分
节点并没有起到实质性的作用,它们的作用仅仅是让请求传递下去,从性能方面考虑,我们要避
免过长的职责链带来的性能损耗。
网友评论