一些个人的整理,仅仅是一些简单的描述,如需深入了解请查找相关资料。
举了一些现实生活中的例子来方便理解,仅供参考,如有错误欢迎指出!
设计模式
原型模式
所有对象都有他的原型,当需要创建该对象时,仅需克隆原型即可实现。
举例:造一辆车子,你只需要拿到设计图,根据设计图来制造,而不是去找一辆车子然后分析它的结构来制造。
伪代码:
// 看做是设计图(原型)
class Car {
constructor(brand) {
this.brand = brand;
}
}
// 可以把 new 操作符看做是制造一辆车
var myCar = new Car("BMW");
单例模式
保证一个类仅有一个实例。
举例:假设一个车站只能有一个售票处。仅仅只需要这个售票处就能卖车票,而不是卖一张票就设立一个售票处。
伪代码:
class TicketOffice {
buyTicket() {
return "一张车票";
}
}
var ticketOffice = null;
function getTicketOffice() {
// 保证只有一个 TicketOffice 实例。
if (ticketOffice === null) {
ticketOffice = new TicketOffice();
}
return ticketOffice;
}
var ticket = getTicketOffice().buyTicket();
策略模式
实现一个功能可以有不同的方法。
举例:从长沙到兰州,可以选择坐火车、坐飞机,也可以选择骑扫帚()。
伪代码:
// 不同交通方式
var transportations = {
train: () => {
console.log("坐火车");
},
airplane: () => {
console.log("坐飞机");
},
broom: () => {
console.log("骑扫帚");
}
}
// 去兰州
function goToLanZhou(way) {
transportations[way]();
}
// 骑扫帚去
goToLanZhou("broom");
代理模式
发生某个行为,必须先经过“审查”。审查中可以修改结果。
举例:进入高铁站,你需要先出示健康码。如果为红色则不放行。
伪代码:
function enterRailwayStation(person) {
console.log(person.name + " 进入了高铁站")
}
function proxyEnterRailwayStation(person) {
// 检查健康码
if (person.healthCode === "Red") {
throw Error("健康码为红色,禁止通行")
}
// 放行
enterRailwayStation(person)
}
var person = {
name: "田所浩二",
healthCode: "Red"
}
proxyEnterRailwayStation(person)
迭代器模式
这个已经非常常见了吧,就是平常我们说的循环遍历。
举例:从装满书的书包里把书一本一本取出来。
伪代码:
var bag = [
"《语文书》",
"《数学书》",
"《魔导书》"
]
for (var book of bag) {
console.log(book)
}
发布-订阅模式
事件发送者发布事件,事件订阅者接收事件。
举例:你订阅了《魔女之旅》。当该番剧更新时你将会收到更新通知。
伪代码:
// 订阅番剧更新消息
majonotabitabi.addEventListener("update", function(episode) {
console.log("《魔女之旅》第 " + episode + "话更新啦!")
})
// 发布番剧更新消息
majonotabitabi.dispatch("update", "1")
命令模式
字面意,就是发出命令,然后执行。
举例:给爷学狗叫三声啊三声
伪代码:
var you = {
bark() {
console.log("汪!")
}
}
you.bark()
you.bark()
you.bark()
组合模式
可以看做是组合了多个命令,然后一键执行。也就是 部分-整体 的结构。
举例:你只需要去肯德基大喊一声“异世相遇,尽享美味”。店员就会给你下单,然后制作汉堡、可乐等食物。你无须关心之后发生了什么(你只需要承受社会性死亡的后果2333)
伪代码:
function createOrder() {
console.log("创建订单")
}
function makeFood() {
console.log("制作食物")
}
function socialDeath() {
console.log("社会性死亡")
}
// 下单
function order() {
console.log("异世相遇,尽享美味")
createOrder()
makeFood()
socialDeath()
}
// 你只需要调用这一个方法即可
order()
模板方法模式
把一段代码的抽象部分提取出来,提高可复用性。
举例:填表,你不需要每次填表都要画表格,你只需要提前制作一份模板,需要的时候直接用就行了。
伪代码:
function makeSentence(obj) {
return "请问您今天要来点" + obj + "吗?"
}
console.log(makeSentence("兔子"))
享元模式
如共享某一对象,需要的时候修改属性即可,节省内存。
举例:一千件衣服不需要去找一千个模特试穿,只需要找一个,换上不同的衣服即可。
伪代码:
class Model {
constructor() {
this.wearing = ""
}
takePhoto() {
console.log("拍照:" + this.wearing)
}
}
var clothes = [
"女仆装",
"魔女装"
]
var model = new Model()
for (var cloth of clothes) {
model.wearing = cloth;
model.takePhoto()
}
职责链模式
不同职责交给不同方法去完成,一般配合单一职责原则使用。
举例:寄快递,你只需要把东西交给快递员,快递员会负责打包和打印运单,到快递站后将会交给送货司机运输到下一站,以此类推。
伪代码:
function sendPacket(packet) {
console.log("你发送了一个包裹" + packet)
makePacket(packet)
}
function makePacket(packet) {
console.log("打包 " + packet)
printOrder(packet)
}
function printOrder(packet) {
console.log("打印订单 " + packet)
// 省略
}
sendPacket("《JS从入门到放弃 》")
中介者模式
在执行一些操作前,执行另外一些操作(比如判断参数是否合法等)
举例:网购一件商品时得先确认有没有库存。
伪代码:
var stock = {
"昏睡红茶": 114514,
"清醒绿茶": 0
}
function isInStock(item) {
return stock[item] > 0
}
function purchase(item) {
// 查询是否还有货
if (!isInStock(item)) {
console.log(item + " 卖光了")
return
}
console.log("买到了 " + item)
}
purchase("昏睡红茶") // 买到了
purchase("清醒绿茶") // 卖光了
装饰者模式
“装饰”方法。如在某方法执行之前,执行日志记录,这也是最常见的一种用法。正如字面意,少了这个装饰基本不会影响原有方法的运行。
举例:每做完一件事,就在 Todo List 上打钩。
伪代码:
function _doHomework() {
console.log("写作业")
}
function doHomework() {
_doHomework();
console.log("作业写完了,可以在 Todo List 上打钩了")
}
doHomework()
状态模式
方法内有内部状态。
举例:电灯有开关两种状态。
伪代码:
function makeBulb() {
var state = "off"
return {
switch() {
if (state === "off") {
console.log("打开电灯")
state = "on"
} else {
console.log("关闭电灯")
state = "off"
}
}
}
}
var bulb = makeBulb()
bulb.switch() // 打开电灯
bulb.switch() // 关闭电灯
适配器模式
如用新方法对输入参数进行处理,以适应旧方法。
举例:电源适配器就是一个例子。通常上面会标上额定电压 110V~220V 以适配不同标准的电源。
function charge220V(device) {
if (device.maxVoltage < 220) {
console.log("Boom!!!")
} else {
console.log("充电中")
}
}
function adapter(device) {
// 这里省略一些代码,毕竟是伪代码
return {
maxVoltage: 220
}
}
var device = {
maxVoltage: 110
}
charge220V(device) // Boom!
charge220V(adapter(device)) // 充电中
设计原则
单一职责原则
每个方法有且只有一个职责。
举例:快递员只负责揽件,打印运单交给业务员,运送包裹交给司机。快递员不能把这些工作全承包了。
最少知识原则
软件实体尽可能少与其他实体发生相互作用。
举例:举办一个大型活动,作为活动举办者不应该去逐个通知,而应该发布公告,参与者应该订阅这个公告事件(这是其中一个例子,还有其他例子不一一列举)。
开放-封闭原则
软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。——《JavaScript 设计模式与开发实践》P263。
举例:一个很知名的例子,两家公司为了解决生生产线生产出空肥皂盒的问题,一家公司花费五百万改造生产线(改造内部),另一家公司则放了个电风扇在旁边吹走空盒子(增加新方法)。
不过个人认为后者在实际情况中只是一种妥协,各有利弊。
参考资料:《JavaScript 设计模式与开发实践》,人民邮电出版社。