针对设计问题的通用解决方案
为什么要学设计模式
- 利于代码复用
- 利于代码稳定可拓展
- 利于代码可读性提升
什么时候需要设计模式
五种设计原则

OCP
开闭原则 (Open Closed Principle)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
if (game === "PUBG") { } else { }
if (game === "LOL") { } else { }
if (game === "PUBG") { } else if (game === "AAA") { } else { }
if (game === "LOL") { } else if (game === "AAA") { } else { }
gameManager(game).setColor();
gameManager(game).openDialog();
function gameManager(game) { return `${game}Manager`; }
const LOLManager = { setColor() { },
openDialog() { }, };
const PUBGManager = { setColor() { },
openDialog() { }, };
class game { constructor(name) { this.name = name; }
setColor() { }
openDialog() { } }
class LOL extends game { openDialog() { } }
class PUBG extends game { setColor() { } }
|
SRP
单一职责 (Single Responsibility Principle)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
class PUBGManager { openDialog() { setPrice(); } }
const game = new PUBGManager(); game.openDialog();
class PUBGManager { constructor(command) { this.command = command; } openDialog(price) { this.command.setPrice(price); } }
class PriceManager { setPrice(price) { } }
const exe = new PriceManager(); const game1 = new PUBGManager(exe);
game1.openDialog(15);
|
DIP
依赖倒置 (Dependency Inversion Principle)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
class Store { constructor() { this.share = new Share(); } }
class Share { shareTo(platform) { } }
const store = new Store(); store.share.shareTo("wx");
class Store { constructor() { this.share = new Share(); this.rate = new Rate(); } }
class Share { shareTo(platform) { } }
class Rate { star(stars) { } }
store.rate.star("wx");
class Rate { init(store) { store.rate = this; } store(stars) { } }
class Share { init(store) { store.share = this; } shareTo(platform) { } }
class Store { static modules = new Map();
constructor() { for (let module of Store.module.values()) { module.init(this); } }
static inject(module) { Store.modules.set(module.constructor.name, module); } }
const rate = new Rate(); Store.inject(rate);
store.rate.start(4);
|
ISP
接口隔离 (Interface Segregation Principle)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
class Game { constructor(name) { this.name = name; } run() { } shot() { } mega() { } }
class PUBG extends Game { constructor() { } }
class LOL extends Game { constructor() { } }
pubg = new PUBG("pubg"); pubg.run(); pubg.shot(); pubg.mega();
class Game { constructor(name) { this.name = name; } run() { } }
class FPS { aim() {} }
class MOBA { TP() {} }
class PUBG extends Game { shot() {} }
|
LSP
里氏替换(Liskov Substitution Principle)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
class Game { start() { } shutdown() { } play() { } }
const game = new Game(); game.play();
class MobileGame extends Game { tombStore() {} play() { } }
const mobile = new MobileGame(); mobile.play();
class Game { start() { } shutdown() { } }
class MobileGame extends Game { tombStore() {} play() { } }
class PCGame extends Game { speed() { } play() { } }
|
三类设计模式

创建型
全局只有一个实例,和状态相关
- 工厂模式: 批量生产同类型应用来满足频繁使用同一类型素材时
- 建造者模式: 需要将元功能模块化解耦,并且需要频繁编排时
- 单例模式: 当全局只有一个实例,注重的是一体化和状态统一。
可使用代理来实现
1 2 3 4 5 6 7 8 9 10 11
| export function singleton(className) { let ins; return new Proxy(className, { construct(target, args) { if (!ins) { ins = new target(...args); } return ins; }, }); }
|
业务场景
- 工厂: 生产不同类型的按钮
- 建造者: Header 组件,包含 title、button、breadcum,生产多种不同元素的组合
- 单例: router、store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
class Shop { create(name) { return new Game(name); } }
class Game { constructor(name) { this.name = name; } init() {} run() {} }
const shop = new Shop(); const pubg = new Game("pubg");
pubg.init(); pubg.run();
class Product { constructor(name) { this.name = name; } init() { return "game: " + this.name; } }
class Skin { constructor(name) { this.name = name; } init() { return "skin: " + this.name; } }
class Shop { constructor() { this.package = ""; } create(name) { this.package = new PackageBuilder(name); } getGamePackage() { this.package.getPackage(); } }
class PackageBuilder { constructor(name) { this.game = new Product(name); this.skin = new Skin(name); } getPackage() { return this.game.init() + this.skin.init(); } }
class PlayStation { constructor() { this.state = "off"; } play() { if (this.state === "on") { return; } this.state = "on"; } shutdown() { if (this.state === "off") { return; } this.state = "off"; } }
PlayStation.instance = undefined; PlayStation.getInstance = function () { return (function () { if (!PlayStation.instance) { PlayStation.instance = new PlayStation(); } return PlayStation.instance; })(); };
const ps = PlayStation.getInstance(); ps.play(); ps.shutdown();
|
结构型
不影响用户体验
- 适配器模式: 中间参数转换,兼容\适配已有方案时
- 装饰器模式: 在已有方案中批量提供\提升相应功能时
- 代理模式: 把调用方和被调用方分离,不直接产生调用关系时
业务场景
- 适配器: 需求中添加适配器做数据结构的转换
- 装饰器: title、button、breadcum 三个组件同时都具有发生改变触发页面刷新的功能
- 代理: ul 标签监听 li 标签,代理到 ul 上监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
class HKDevice { getPlug() { return "港行插头"; } }
class Target { constructor() { this.plug = new HKDevice(); } getPlug() { return this.plug.getPlug() + "+ 插头转接器"; } }
const target = new Target(); target.getPlug();
class Device { create() { console.log("PlayStation4"); } } class Phone { create() { console.log("iphone13"); } }
class Decorator { constructor(device) { this.device = device; } create() { this.device.create(); this.update(this.device); } update(device) { console.log(device + "pro"); } }
const device = new Device(); device.create();
const newDevice = new Decorator(device); newDevice.create();
class Game { play() { return "playing"; } }
class Player { constructor(age) { this.age = age; } }
class GameProxy { constructor(player) { this.player = player; } play() { return this.player.age < 16 ? "too young to play" : new Game().play(); } }
|
行为型
节点互斥、前后链式相连
- 命令模式: 具有发出方 + 媒介 + 接收方 的完整流程时
- 模板模式: 对于基础说明书,进行的一次实际业务结合操作时
- 观察者模式: 通过观察者,可以让被观察者实时接收消息,平且触发一定的业务操作时
- 职责链模式: 独立指责单元链式执行,逐步操作流程时
业务场景
- 命令: 组件 A 通知组件 B,媒介抽象为数据处理中间层
- 模板: echarts、canvas、config…
- 观察者: 输入框变化,下拉框实时更新选项
- 职责链: 提交表单,链式调用 validate,依次执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
class Receiver { execute() { console.log("开始奔跑"); } }
class Operator { constructor(command) { this.command = command; } run() { this.command.execute(); } }
class Command { constructor(receiver) { this.receiver = receiver; } execute() { this.receiver.execute(); } }
const soldier = new Receiver(); const order = new Command(soldier); const player = new Operator(order); player.run();
class Device { constructor(executePipeLine) { } powerOn() { console.log("开机"); } login() { console.log("登录账号"); } clickStart() { console.log("开始游戏"); } enterGame() { console.log("进入战场"); } play() { this.powerOn(); this.login(); this.clickStart(); this.enterGame(); } }
class MediaCenter { constructor() { this.state = ""; this.observers = []; } attach(observer) { this.observers.push(observer); } getState() { return this.state; } setState(state) { this.state = state; this.notifyAllobservers(); } notifyAllobservers() { this.observers.forEach((ob) => { ob.update(); }); } }
class Observer { constructor(name, center) { this.name = name; this.center = center; this.center.attach(this); } update() { return { name: this.name, state: this.center.getState(), }; } } const center = new MediaCenter(); const ps = new Observer("ps", center);
center.setState("on");
class Action { constructor(name) { this.name = name; this.nextAction = null; } setNextAction(action) { this.nextAction = action; } handle() { console.log(this.name + "请审批"); if (this.nextAction !== null) { this.nextAction.handle(); } } }
const dad = new Action("爸"); const mom = new Action("妈"); const wife = new Action("夫人");
dad.setNextAction(mom); mom.setNextAction(wife);
dad.handle();
|