你可以跳过的部分
传统的设计模式有23种,是前人积累下来经验的总结。设计模式离我们其实不远,日常开发中我们或多或少有使用到相关的设计模式,如果熟练使用这些设计模式,我们的代码质量也会提高并且易扩展、易阅读。就像我们玩LOL(英雄联盟),设计模式就像那些套路,好的套路使得你从一开始就很有优势,更加容易赢得比赛。
五大原则
开闭原则--OCP(open closed principle)
对拓展开放、对修改关闭
已有的场景下,对于需要拓展的功能进行开放、拒绝直接的功能修改
class game {
constructor(name) {
this.name = name;
}
setColor() {
console.log('这是有颜色的');
}
openDialog() {
console.log('付款框');
}
}
class LOL extends game {
openDialog() {
console.log('折扣');
}
}
class PUBG extends game {
setColor() {
console.log('高亮');
}
openDialog() {
console.log('付款');
}
}
单一职责原则--SRP(single responsibility principle)
通过解耦让每一个职责更加的独立
一个功能制作一件事
class CAT {
constructor(command) {
this.command = command
}
eat(food) {
console.log(`吃了${food}`);
this.command.drink() // 吃+喝
}
}
class Drink {
drink(water) {
console.log('农夫山泉有点甜');
}
}
const drink = new Drink() // new一只叫timor的猫
const timorLife = new CAT(drink)
timorLife.eat('猫条') // 吃了猫条 农夫山泉有点甜
依赖倒置原则--DIP(Depend inversion principle)
上层不应依赖下层实现,面向对象进行coding,而不是对实现进行coding,降低需求与实现的耦合
// 评分功能
class Store {
constructor() {
this.share = new Share();
this.rate = new Rate();
}
}
class Share {
shareTo() {
// 分享到不同平台
}
}
class Rate {
star(stars) {
// 评分
}
}
const store = new Store();
store.rate.stars('5');
// 使用依赖倒置原则对其进行重构
// 目标: 暴露挂载 => 动态挂载
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.modules.values()) {
module.init(this);
}
}
// 注入功能模块
static inject(module) {
Store.modules.set(module.constructor.name, module);
}
}
// 依次注册完所有模块
const rate = new Rate();
Store.inject(rate);
// 初始化商城
const store = new Store();
store.rate.star(4);
接口隔离原则--ISP(Interface segregation principle)
多个专业的接口比单个胖接口好用
class Game {
constructor(name) {
this.name = name;
}
run() {
// 跑
}
}
class PUGB extends Game {
constructor() {
super()
// pubg constructor
}
shot() {
console.log('射击');
}
}
class LOL extends Game {
constructor() {
super()
// lol constructor
}
mega() {
console.log('开大招');
}
}
里氏替换原则--LSP(Richter's substitution principle)
子类能够覆盖父类,父类能够出现的地方子类就能出现
class Game {
start() {
// 开机
console.log('start');
}
shutdown() {
// 关机
console.log('shutdown');
}
}
class MobileGame extends Game {
tombStone() {
console.log('tombStone');
}
play() {
console.log('playMobileGame');
}
}
class PC extends Game {
speed() {
console.log('speed');
}
play() {
console.log('playPCGAME');
}
}
设计模式
创建型(创建元素 => 规范创建步骤)
模式场景
-
批量生产同类型应用来满足频繁使用同一种类型需求时 - 工厂模式
-
当我们需要模块化拆分一个大模块,同时使模块间独立解耦分工 - 建造者模式
-
全局只需要一个实例,注重统一一体化 - 单例
实际应用
Button Producer:生产不同类型的按钮 => 生产多个本质相同,利用传参区分不同属性的元素 => 工厂
全局应用 router store => 只需要一个实例 => 单例
页头组件Header: 包含了title、button、breadcum => 生产多重不同类型的元素 => 建造者
工厂模式:生产同类型商品,隐藏创建过程、暴露共同接口
class Shop {
create(name) {
return new Game(name);
}
}
class Game {
constructor(name) {
this.name = name;
}
init() {
console.log('init');
}
run() {
console.log('run');
}
}
const shop = new Shop();
const pubg = new Game('pubg');
pubg.init();
pubg.run();
建造者模式:独立生产商品,拆分简单模块、独立执行 => 注重过程与搭配
每个模块独立解耦,而建造者负责创建串联整体系统
例子: 优惠套餐单元,商品 + 皮肤 进行打折售卖
class Product {
constructor(name) {
this.name = name;
}
init() {
console.log('Product init');
}
}
class Skin {
constructor(name) {
this.name = name;
}
init() {
console.log('Skin init');
}
}
class Shop {
constructor() {
this.package = '';
}
create(name) {
this.package = new PackageBuilder(name);
}
getGamePackage() {
return 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();
}
}
单例模式:全局只有一个实例
例子:vue-router
结构型(代码结构)
优化结构的实现方式
模式场景
中间转换参数、保持模块间独立的时候 - 适配器模式
附着于多个组件上,批量动态赋予功能的时候 - 装饰器模式
将代理对象与调用对象分离,不直接调用目标对象 - 代理模式
实际应用
-
两个模块:筛选器和表格,需要做一个联动。但筛选器的数据不能直接传入表格,需要做数据结构转换 => 模块之间独立,需要做数据结构转换 => 适配器模式
-
目前有按钮、title、icon三个组件。希望开发一个模块,让三个组件同时具备相同功能 => 套一层装甲对于每个组见
有统一的能力提升,且可以动态添加功能进行拓展 => 装饰器模式 3. ul中多个li,每个li上的点击事件 => 利用冒泡做委托,事件绑定在ul上 => 代理模式
适配器模式:适配已有方案
适配独立模块,保证模块间的独立解耦且连接兼容
// 需求: 买了一个港行PS,插座是国标
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('iphone18');
}
}
class Decorator {
constructor(device) {
this.device = device;
}
create() {
this.device.create();
this.update(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();
}
}
const player = new Player(18);
const game = new GameProxy(player);
game.play();
行为型(模块行为总结)
不同的对象之间划分责任和算法的抽象化
模式场景
发出指令,中间层传递命令本身,命中包含执行对象 - 命令模式
通过模板定义执行顺序,做独立操作 - 模板模式
通过观察者,可以让被观察值统一发生变化,触发相应依赖值的统一更新 - 观察者模式
独立职责的单元通过链式执行,逐步操作流程 - 职责链
实际应用
-
提交表单进行表单逐行校验,链式调用validate,依次执行 => 职责链
-
echart准备工作:canvas、config、init、draw(),规划顺序执行 => 模板模式
-
调度器在接受到一组新的数据时候,解析数据,并且根据数据类型包裹在对象中传递到下级helper,helper 再去执行相应操作 => 命令模式
-
输入框输入的值去判断下拉框显示与否 => 观察input设置show => 观察者模式
命令模式:包裹传递命令
请求以命令的形式包裹在对象中,并传给调用对象
// 接受者
class Receiver {
execute() {
console.log('角色开始奔跑');
}
}
// 触发者
class Operator {
constructor(command) {
this.command = command;
}
run() {
console.log('请给我爬');
this.command.execute();
}
}
// 指令器
class Command {
constructor(receiver) {
this.receiver = receiver;
}
execute() {
console.log('执行命令');
this.receiver.executer();
}
}
const soldier = new Receiver();
const order = new Command(soldier);
const player = new Operator(order);
player.run();
模板模式: 重编排,易扩展
在模板中,定义好每个方法的执行步骤,方法本身关注自己的事情
class Device {
constructor(executePipeLine) {
// executePipeLine……
}
powerOn() {
console.log('打开电源');
}
login() {
console.log('登录账号');
}
clickIcon() {
console.log('点击开始游戏');
}
enterGame() {
console.log('进入战场');
}
play() {
this.powerOn();
this.login();
this.clickIcon();
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() {
console.log(`${this.name} update, state: ${this.center.getState()}`);
}
}
const center = new MediaCenter();
const ps = new Observer('ps', center);
const tv = new Observer('tv', center);
center.setState('on');
职责链模式:单向链执行
1.链式调用 2.职责独立 3.顺序执行
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();