『面试的底气』—— 设计模式之依赖倒置原则

1,605 阅读4分钟

前言

在学习设计模式之前,首先要认识到设计模式是个编程思想,对任何编程语言都适用。其次要从设计模式的原则开始学习,故本文将详细介绍设计模式的原则之一依赖倒置原则

官方定义

高层模块不应该依赖低层模块。两个都应该依赖抽像。

抽像不应该依赖细节,细节应该依赖抽像。

自己的理解

首先举几个生活中的例子来了解一下高层模块和低层模块。

电脑主机大家都很熟悉吧,主机中有主板、CPU、内存条、显卡、硬盘,其中主板属于高层模块,CPU、内存条、显卡、硬盘属于低层模块。这么归属是由一定依据的,低层模块具备易换性,高层模块具备不易替换性。试想一下,换一个主板,要先把CPU、内存条、显卡、硬盘拆掉,然后再更换主板,要动到所有配件。那么换一个内存条呢,只要把内存条从主板上把下来替换上去就行。

再举一个例子加深一下对高层模块的不易替换性和低层模块的易替换性的理解。假设你开了一家奶茶店,其中奶茶店就是高层模块,所卖的奶茶是低层模块。在生意不好的时候,换几种奶茶卖容易,还是重新开一家奶茶店容易。

高层模块可看作一个平台,把低层模块放在这个平台上,才能实现其作用。比如把CPU、内存条、显卡、硬盘安置到主板上才能其作用,把奶茶放在奶茶店中才能卖出去。

理解完什么是高层模块和低层模块,再来理解一下为什么要依赖倒置,倒置是如何操作的。还是用开奶茶店的例子来做解释。

假设你要开一家奶茶店,按正常人思维,先想要在哪里开店,要请多少员工,最后在决定卖什么奶茶。然而有些老板想太多了,都想到要如何生产奶茶了。这就是本末倒置了,应该是奶茶依赖奶茶店才能卖出去,所以要依赖倒置一下。这也是依赖倒置原则中的高层模块不应该依赖低层模块,奶茶店不应该依赖奶茶,奶茶种类千千万万,大不了换一种奶茶就行。

上面提到过奶茶依赖奶茶店才能卖出去,还要再补充一下,奶茶不能依赖一家奶茶店,这家奶茶店倒闭了,换一家奶茶店卖就是了。这样奶茶店和奶茶之间都不互相依赖了,这也不行。根据依赖倒置原则中的两个都应该依赖抽像来解决该问题。用代码来模拟一下解决过程,从千千万万奶茶(具体类)中抽像出一个抽像类MilkTea,因为规定了奶茶(具体类)中必须提供一个sell方法来卖奶茶,所以在抽像类MilkTea中实现一个sell方法来卖奶茶,sell方法接收一个奶茶(具体类)实例化后的对象,执行对象中的sell方法,就是卖奶茶。

在奶茶店(高层模块)中继承抽像类MilkTea创建了一个备货的功能Stock类,老板执行new Stock([AMilkTea, BMilkTea, CMilkTea])[AMilkTea, BMilkTea, CMilkTea]为要备货奶茶种类清单,得到一堆奶茶goods,然后有人来买AMilkTea奶茶,老板就执行goods.sellTea(AMilkTea),如何AMilkTea奶茶有生产,就会返回“卖出一杯A奶茶”,没有生产,则返回“该种奶茶未生产”。在此过程,奶茶店(高层模块)不要去管奶茶(低层模块)如何生产(实例化),如何一种奶茶(低层模块)停产了(删除了),也不会影响奶茶店的正常营业,只要告诉顾客“该种奶茶未生产”。

class MilkTea {
  sell(milkTea) {
    if (milkTea.sell instanceof Function) {
      milkTea.sell();
    }else{
        console.log('该种奶茶暂不销售')
    }
  }
}
class Stock extends MilkTea {
  constructor(teaTypes) {
    super();
    this.teas = {};
    teaTypes.forEach(item => {
      const tea = new item();
      this.teas[item] = tea;
    })
  }
  sellTea(teaType) {
    if (this.teas[teaType]) {
      this.sell(this.teas[teaType])
    } else {
      console.log('该种奶茶未生产')
    }
  }
}
class AMilkTea {
  constructor() {}
  sell() {
    console.log('卖出一杯A奶茶')
  }
}
class BMilkTea {
  constructor() {}
  sell() {
    console.log('卖出一杯B奶茶')
  }
}
const goods = new Stock([AMilkTea, BMilkTea, CMilkTea]);
goods.sellTea(AMilkTea);// 卖出一杯A奶茶
goods.sellTea(BMilkTea);// 卖出一杯B奶茶
goods.sellTea(CMilkTea);// 该种奶茶未生产

其中if (milkTea.sell instanceof Function)体现了依赖倒置原则中的抽像不应该依赖细节,细节应该依赖抽像,如果一个奶茶(低层模块)没有提供卖奶茶的方法,那就不卖了(不执行),不会影响奶茶店营业(程序正常运行),只需告诉顾客“该种奶茶暂不销售”。