软件设计的开闭原则与倒置原则(读书笔记)

本文是关于软件设计的读书笔记,主要探讨了开闭原则和依赖倒置原则。通过策略模式、适配器模式、观察者模式和模板方法模式来实现开闭原则,以提高代码的可扩展性和可维护性。同时,解释了依赖倒置原则,强调高层模块应依赖抽象,而非具体实现,以增强模块的复用性和降低维护难度。

一、开闭原则

软件实体(模块、类、函数等等)应该对扩展是开放得,对修改是关闭的。

1.1解释 :
1.对扩展是开发的 :当需求变更时,可以对模块进行扩展,使其满足需求。
2.对修改是关闭的 :对软件实体进行扩展时,不需要改动当前软件实体,不用更改代码,对于已经编译打包的模块不需要重新编译。
1.2开闭原则的实现
1.2.1使用策略模式实现开闭原则
策略模式 :多个策略实现同一个策略接口,编程的时候client 程序依赖策略接口,
运行期根据不同上下文向 client 程序传入不同的策略实现。

在这里插入图片描述
Button依赖于ButtonServer,由Dailer实现ButtonServer接口,当Button按下时调用ButtonServer中的buttonPressed方法,由于是Dailer实现了ButtonServer接口,实际上调用的是Dailer的buttonPressed方法,使得Button不会直接依赖Dailer,而且只要是实现了ButtonServer接口的类,都可以使用Button,不需要更改Button代码,使得Button满足开闭原则。

就是说本来Button是直接依赖Dailer,我们需要在Button代码中直接去判断用户的输入,并通过if/switch选择不同的功能,当我们需要对功能进行拓展时候,就要去改变Button代码,比如在if/switch中增加一些判断,这样Button就不再满足开闭原则,在之后的软件迭代中Button代码会变得臃肿,难以维护和复用,通过策略模式使得Button满足了开闭原则,之后要对Button的功能进行扩展只需要去实现ButtonServer接口,将新增的功能写在实现类中即可。

1.2.2使用适配器模式实现开闭原则
适配器模式 :是一种结构模式,用于将两个不匹配的接口适配起来,使其能够正常工作。

在上面的策略模式中Button满足了开闭原则,但是Dailer不满足开闭原则,因为在Dailer实现了ButtonServer接口后,需要在Dailer中根据Button传的参数使用if/else或者switch/case选择功能
在这里插入图片描述
增加两个适配器DigitButtonDailerAdepter、SendButtonDailerAdepter,由适配器实现 ButtonServer 接口,在适配器的 buttonPressed 方法中调用 Dailer 的 enterDigit 方法和 dail 方法,而 Dailer 类保持不变,Dailer 类实现开闭原则。

可以理解为适配器充当了中间人,连接Button与Dailer,所有的代码改动在适配器中进行,使得Button与Dailer满足开闭原则

1.2.3使用观察者模式实现开闭原则
观察者模式 :是一种行为模式,解决一对多的对象依赖关系,将被观察者对象的行为通知到多个观察者,也就是监听者对象

通过上面的策略模式与适配器模式,使得Button员Dailer都符合了开闭原则,但是按钮与功能之间都是一对一的关系,在我们需要一个按钮实现多个功能时,需要在适配器中进行使用修改代码,又不符合开闭原则了

在这里插入图片描述
Button类中增加了成员变量List与和成员方法addListener,通过addListener将多个观察者添加到List中,当按钮需要控制其他功能时候只需要将实现了ButtonListener的类添加到Button的List中即可,当事件发生时通过Button中的press方法通知List中的所有观察者,从而实现一对多的关系,并且满足开闭原则

观察者模式实现代码 提取码:txwv

1.2.4使用模板方法模式实现开闭原则
模板方法模式 :就是在父类中用抽象方法定义计算的骨架和过程,而抽象方法的实现则留在子类中。

如果在按钮按下时还需要有操作,比如按下时按钮会亮灯,那么在Button的press方法中又要进行增加代码判断。

在这里插入图片描述
在Button中定义抽象方法,具体的按钮,比如SendButton,DigitButton实现这个方法,并在press方法中调用onPress方法,通过模板方法模式,子类自己定义在按钮按下时的操作,使得Button满足开闭原则


abstract void onPress();

public void press() {
     onPress();
     for (ButtonListener listener : listeners) {
         listener.buttonPressed();
     }
}

二、依赖倒置原则

高层模块不应该依赖低层模块,二者都应该依赖抽象
抽象不应该依赖具体实现,具体实现应该依赖抽象

一般的应用程序中,策略层会依赖方法层,业务逻辑层会依赖数据存储层,这种分层依赖的方式缺点 :
维护困难,由于低层模块更多的是技术细节,高层模块依赖低层模块,就是业务逻辑依赖技术细节,技术细节的改变会影响业务逻辑,因为技术细节的改变而影响业务代码,这是不应该的
复用困难,越是高层模块复用的价值越高,如果高层模块依赖低层,那么对高层模块的依赖将会导致对底层模块的连带依赖,使复用变得困难。

层次依赖:
在这里插入图片描述

2.1依赖倒置的关键

每个高层模块都为它所需要的服务声明一个抽象接口,而低层模块则实现这些抽象接口,高层模块通过抽象接口使用低层模块。

在这里插入图片描述
依赖倒置原则中,除了具体实现要依赖抽象,最重要的是,抽象是属于谁的抽象。接口被高层模块定义,高层模块拥有接口,低层模块实现接口。不是高层模块依赖底层模块的接口,而是低层模块依赖高层模块的接口,从而实现依赖关系的倒置。

2.2依赖倒置实现高层模块复用

在这里插入图片描述
lamp做出的改变会使得button也要做出改变,列如 :原本lamp的turnOn函数进行了改变,变成了flash函数,button也要做出改变,因为button直接依赖于lamp的功能

为了解决直接依赖的问题,Button定义出它所需要的功能在ButtonServer接口中,底层lamp去实现ButtonServer接口即可,Button不用管lamp的改变,因为他们都依赖于一个共通原则,即ButtonServer

Button 可以复用控制其他目标对象,比如电机,或者任何由按钮控制的设备,只要这些设备实现 ButtonServer 接口就可以了。

在这里插入图片描述

依赖倒置原则通俗说就是,高层模块不依赖低层模块,而是都依赖抽象接口,这个抽象接口通常是由高层模块定义,低层模块实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值