900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 如何修改代码又不违背开闭原则呢?看这里

如何修改代码又不违背开闭原则呢?看这里

时间:2018-08-06 07:42:42

相关推荐

如何修改代码又不违背开闭原则呢?看这里

前言

看了前一篇重构之后的代码,你可能还会有疑问:

在添加新的告警逻辑时,改动二(添加新的 handler 类)是基于扩展而非修改的方式来完成的,但改动一、三、四貌似不是基于扩展而是基于修改的方式来完成的,

那改动一、三、四不就违背了开闭原则吗?

public class Alert {// 代码未改动... }public class ApiStatInfo {// 省略 constructor/getter/setter 方法private String api;private long requestCount;private long errorCount;private long durationOfSeconds;private long timeoutCount; // 改动一:添加新字段}public abstract class AlertHandler {// 代码未改动... }public class TpsAlertHandler extends AlertHandler {// 代码未改动...}public class ErrorAlertHandler extends AlertHandler {// 代码未改动...}// 改动二:添加新的 handlerpublic class TimeoutAlertHandler extends AlertHandler {// 省略代码...}public class ApplicationContext {private AlertRule alertRule;private Notification notification;private Alert alert;public void initializeBeans() {alertRule = new AlertRule(/*. 省略参数.*/); // 省略一些初始化代码notification = new Notification(/*. 省略参数.*/); // 省略一些初始化代码alert = new Alert();alert.addAlertHandler(new TpsAlertHandler(alertRule, notification));alert.addAlertHandler(new ErrorAlertHandler(alertRule, notification));// 改动三:注册 handleralert.addAlertHandler(new TimeoutAlertHandler(alertRule, notification));}//... 省略其他未改动代码...}public class Demo {public static void main(String[] args) {ApiStatInfo apiStatInfo = new ApiStatInfo();//... 省略 apiStatInfo 的 set 字段代码apiStatInfo.setTimeoutCount(289); // 改动四:设置 tiemoutCount 值ApplicationContext.getInstance().getAlert().check(apiStatInfo);}

我们先来分析一下改动一:往ApiStatInfo类中添加新的属性timeoutCount

我们不仅往ApiStatInfo类中添加了属性,还添加了对应的getter/setter方法。那这个问题就转化为:给类中添加新的属性和方法,算作 “修改” 还是 “扩展”?

我们再一块回忆一下开闭原则的定义:软件实体(模块、类、方法等)应该 “对扩展开放、对修改关闭”。

从定义中,我们可以看出,开闭原则可以应用在不同粒度的代码中,可以是模块,也可以是类,还可以是方法(及其属性)。

同样一个代码改动,在粗代码粒度下,被认定为 “修改”,在细代码粒度下,又可以被认定为 “扩展”。

比如,改动一,添加属性和方法相当于修改类,在类这个层面,这个代码改动可以被认定为 “修改”;但这个代码改动并没有修改已有的属性和方法,在方法(及其属性)这一层面,它又可以被认定为 “扩展”。

我们回到这条原则的设计初衷:只要它没有破坏原有的代码的正常运行,没有破坏原有的单元测试,我们就可以说,这是一个合格的代码改动

接下来再来分析一下改动三改动四:在ApplicationContext类的initializeBeans ()方法中,往alert对象中注册新的timeoutAlertHandler;在使用Alert类的时候,需要给check ()函数的入参apiStatInfo对象设置timeoutCount的值。

这两处改动都是在方法内部进行的,不管从哪个层面(模块、类、方法)来讲,都不能算是 “扩展”,而是地地道道的 “修改”。

不过,有些修改是在所难免的,是可以被接受的。

在重构之后的 Alert 代码中,我们的核心逻辑集中在 Alert 类及其各个 handler 中,当我们在添加新的告警逻辑的时候,Alert 类完全不需要修改,而只需要扩展一个新 handler 类。如果我们把 Alert 类及各个 handler 类合起来看作一个 “模块”,那模块本身在添加新的功能的时候,完全满足开闭原则。

而且,我们要认识到,添加一个新功能,不可能任何模块、类、方法的代码都不 “修改”,这个是做不到的。类需要创建、组装、并且做一些初始化操作,才能构建成可运行的的程序,这部分代码的修改是在所难免的。我们要做的是尽量让修改操作更集中、更少、更上层,尽量让最核心、最复杂的那部分逻辑代码满足开闭原则。

更多java原创阅读:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。