「js设计模式」迪米特法则,中介者模式及其实战意义

557 阅读3分钟

概念

迪米特法则

Don't talk to strangers. 不要和陌生人说话

迪米特法则又称为最小知识原则,他被描述为一种代码设计的基本原则.他要求一个对象对其他对象应该有最少的了解.这个法则认为,任意对象应当也只能调用如下对象:

  • 对象本身
  • 作为实参传入的对象
  • 在方法内创建的对象

从业务理解的方向上来说,我们需要了解类与类之间的关系,哪些类之间是可以直接产生业务协作的,哪些类之间又是应该对彼此知之甚少的?这边给一个demo来帮助了解.

Demo

现在有业务场景如下:

病人需要支付看病费用,于是他走到了支付窗口拿出了钱包,准备开始付钱

// 病人

class Patient {

    name: string

    patientId: string | number

    MineWallet: Wallet

    
    constructor() {
        
        this.name = ''

        this.init()

    }

    /**
     * 获取个人信息
     */
    getUserInfo = async () => {

        let res = await apiGetUserInfo()

        this.patientId = res.patientId

        this.name = res.name

    }
    /**
     *  初始化钱包
     */
    initWallet = async () => {

        let mineWallet = new Wallet({ patientId: this.patientId })
        
        mineWallet.init()

        this.MineWallet = mineWallet

    }

    /**
     * 初始化
     */
    init = async() =>  {

        await this.getUserInfo()

        this.initWallet()
    }

    // 获取钱包
    getWallet = () => {

        return this.MineWallet

    }

}

// 钱包

class Wallet extends Object{

    money: number

    patientId: number | string

    constructor(params) {

        super(params)

        const { patientId } = params

        this.money = 0

        this.patientId = patientId

    }

    // 获取余额
    getMoney = async () => {
        
        let res = await apiGetMoney(this.patientId)

        this.money = this.money

        return this.money
    }

    setMoney = async (money: number) => {

        let res = await apiSetMoney(this.patientId)
    }

        // 初始化钱包
    init = async () => {
    
        this.patientId ? 
            
            this.getMoney():
        
            console.log('出问题')
        
    }
}

// 支付窗口

class PayWindow {

    pay = async(patient: Patient, money: number) => {

        let thiswallet: Wallet

        thiswallet = patient.getWallet()

        let nowMoney = await thiswallet.getMoney()

        if (nowMoney > money) {

            thiswallet.setMoney(nowMoney - money)

        } else {
            
            console.log('出问题')

        }

    }

}

这样子的设计其实就违反了迪米特法则.我们不如将这一串代码语意化

病人: 嘿哥们 我要付钱!

收银台工作员: 好的老弟,我是不会告诉你要花多少钱的,你先把钱包拿出来给我,我来看看够不够!

病人: ??? (但还是交出了钱包)

收银台工作员: 很好,够了,看不出你还挺有钱,钱付好了你可以走了.

看出来了吗?问题就在于收银台工作员不应该直接和钱包发生交互,根据迪米特法则,payWindow和Wallet两个对象之间应该是无知的.

那么正确的流程是什么呢? 其实也很简单.将pay方法写在patient类中,payWindow只会去调用patient类中的pay方法.

// 病人

class Patient {

    //.....

    pay = async (money: number) => {

        let nowMoney = await this.MineWallet.getMoney()

        if (nowMoney > money) {

            this.MineWallet.setMoney(nowMoney - money)

        } else {
            
            console.log('出问题')

        }

    }

}

class PayWindow {

    pay = async(patient: Patient, money: number) => {

        patient.pay(money)

    }

}

再次语意化一下:

病人: 嘿哥们儿我要付钱!

收银台工作人员: 共计199元.

病人: 让我看看...钱够了,给你.

收银台工作人员: 好的.

中介者模式

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。

优点:

  • 降低了类的复杂度,将一对多转化成了一对一。
  • 各个类之间的解耦,减少对象之间的关联性,让每一个对象都能够独立
  • 符合迪米特原则。
  • 不会引入太多其他的系统
  • 系统被依赖的程度降低

缺点:

  • 中介类可能会因为功能量的增加而变得很大,需要配套使用其他的设计模式使用.

在上面的例子中.patient类就作为了payWindow和wallet的中介类.