五大设计原则与常用设计模式

224 阅读4分钟

五大设计原则

单一职责原则

通过解耦,让每个模块的职责更加独立

依赖倒置原则

上层模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。核心思想是:要面向接口编程,不要面向实现编程。

/**
 * 首先实现应用商店的分享功能,后来又增加了评分功能
*/
// 底层模块, 应用商店部分
class Store {
    constructor(){
        for(let module of Store.modules.values()){
            module.init(this)
        }
    }
    static modules = new Map()
    static inject(module){
        Store.modules.set(module.constructor.name, module)
    }  
}
// 实现分享功能
class Share{
    init(store){
        store.share = this
    }
    shareTo(){
        console.log('分享了功能')
    }
}

// 新加评分功能
class Rate{
    init(store){
        store.rate = this
    }
    rate(){
        console.log('评分了')
    }
}
// 先注册这两个功能
const share = new Share()
const rate = new Rate()
Store.inject(share)
Store.inject(rate)
const store = new Store()
// 调用功能
store.share.shareTo()
store.rate.rate()

开放-封闭原则

对上层功能扩展的开放,对底层代码修改的封闭

     /**
       * 实现一个每种动物叫的功能
     */
    // 第一种
    
    // 底层代码部分
    class MakeSound {
        constructor(animal){
            animal.sound()
        }
    }
    
    // 功能拓展部分
    
    class Duck {
       sound(){
           console.log('嘎嘎嘎')
       }
    }
    const duck = new Duck()
    new MakeSound(duck)
    
    // 新加动物的时候,只需要增加拓展部分,不需要对基础代码做变动
        class Chicken {
            sound(){
                console.log('咯咯咯')
            }
        }
        const chicken = new Chicken()
        new MakeSound(chicken)
        
    // 第二种
    
    // 底层代码部分
    class Animal2 {
        sound(){
            console.log('')
        }
    }
    // 功能拓展部分
    class Duck2 extends Animal2{
        sound(){
            console.log('嘎嘎嘎')
        }
    }
    const duck2 = new Duck2()
    duck2.sound()

接口隔离原则

接口应该尽可能精简

// 有一个动物大类,新建海洋动物类和陆地动物类
class Animal{
    talk(){}
    run(){}
    swim(){}
}
class Sea extends Animal{}
class Land extends Animal{}

// 修改一下
class Animal{
    talk(){}
}
class Sea extends Animal{
    swim(){}
}
class Land extends Animal{
    run(){}
}

里氏替换原则

子类可以拓展接口,不能改变接口,不要破坏继承体系

常用设计模式

创建型

工厂模式

生产同类型产品

class Animal{
    constructor(name){
        this.animal = name
    }
}
const duck = new Animal('duck')
const pig = new Animal('pig')

建造者模式

将一个负责对象的构建层与其表示层互相分离

// 实现一个优惠套餐单元, 皮肤+商品套餐打折售卖
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)
    }
    get(){
        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()
    }
}    

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点

// 页面需要一个弹框
class Dialogue{
    open(){}
}
class Load(){
    constructor(){
        this.dialogue = ''
    }
    createdialogue(){
        if(this.dialogue){
            return this.dialogue.open()
        } else {
            this.dialogue = new Dialogue
            return this.dialogue.open()
        }
    }
}
const load = new Load()
load.createdialogue()

// 也可以用闭包

function Dialogue(){
    this.open = () => { console.log('open dialogue')}
}

function Load(){
    this.createdialogue = () => {
           let dialogue = null
        return () => {
            if(dialogue){
                return dialogue.open()
            } else {
                dialogue = new Dialogue
                return dialogue.open()
            }
        }
    }
}
let load = new Load()
let dialogue = load.createdialogue()
dialogue()

结构型

适配器模式

适配已有方案 适配器一般在开发中,用作数据格式的适配比较多,本来定义的数组类型的,现在返回的是一个大对象,这时候就可以不改变原有代码,而是在外面加一个适配器,将对象转为数组结构

装饰器模式

增强已有方案

// 先有一个人,然后我们不断的给这个人加buff
class Person{
    constructor(name){
        this.name = name
    }
}
class Buff{
    constructor(person){
        this.person = person
    }
    fly(){
        console.log('会飞')
    }
}
const lisi = new Person('lisi')
let bufflist = new Buff(lisi)
bufflist.fly()

代理模式

为访问对象提供一个代理,控制对它的访问

// 进入一款游戏之前,需要对玩家的年龄进行验证
class Game{
    play(){}
}
class Player{
    constructor(age){
        this.age = age
    }
}
class GameProxy{
    constructor(player){
        this.player = plauer
    }
    play(){
        if(this.player.age >= 18){
            return new Game().play()
        }
    }
}
let player = new Player(19)
new GameProxy(player)

行为型

命令模式

包裹传递命令

class Receiver{
    excute(){
        console.log('跑')
    }
}
class Operator{
    constructor(command){
        this.command = command
    }
    run(){
        this.command.excute()
    }
}
class Command{
    constructor(receiver){
        this.receiver = receiver
    }
    execute(){
        console.log('执行命令')
        this.receiver.excute()
    }
}

const solider = new Receiver()
const order = new Command(solider)
const player = new Operator(order)
player.run()

模板模式

封装好固定的流程

// 把东西放进冰箱的步骤
class Process{
    constructor(name){
        this.name = name
    }
    openDoor(){}
    put(){
        console.log('put' + this.name)
    }
    closeDoor(){}
    init(){
        this.openDoor()
        this.put()
        this.closeDoor()
    }
}

观察者模式

模块间的互通

// 顾客们在销售那里留下信息,有房源的时候,销售第一时间通知他们
class Seller {
    constructor(){
        this.observer = new Set()
    }
    subscribe(customer){
        this.observer.add(customer)
    }
    notify(){
        this.observer.forEach(customer => {
            customer.receive()
        })
    }
}

class Customer {
    constructor(name){
        this.name = name
    }
    receive(){
        console.log(this.name + '收到')
    }
}
let seller = new Seller()
let lisi = new Customer('lisi')
seller.subscribe(lisi)
let zhangsan = new Customer('zhangsan')
seller.subscribe(zhangsan)
seller.notify()

职责链模式

多个对象都有机会处理请求,避免请求处理处理模块的耦合, 将这些对象连成一条链,沿着这条链传递请求,直到4有个对象能处理它

// 根据一个变量的值来确定执行
// 普通写法
function excute(x) {
    if(x === 1 ){
        console.log('这是1')
    } else if(x === 2){
        console.log('这是2')
    } else if(x === 3){
        console.log('这是3')
    }
}
// 职责链模式
function excute(x){
    excute1(x)
}
function excute1(x){
    if(x === 1){
        console.log('这是1')
    } else{
        excute2(x)
    }
}
function excute2(x){
    if(x === 2){
        console.log('这是2')
    } else{
        excute3(x)
    }
}
function excute3(x){
    if(x === 3){
        console.log('这是3')
    } else{
       console.log('啥也不是')
    }
}

参考书籍:<JavaScript设计模式与开发实践> <JavaScript设计模式>