王大虎

王大虎:扩展后的书店售书类图

王大虎

OffNovelBook类继承了NovelBook,并覆写了getPrice方法,不修改原有的代码。新增加的子类OffNovelBook如代码清单6-4所示。

代码清单6-4 打折X的小说类

 

* * *

 

public class OffNovelBook extends NovelBook { public OffNovelBook(String _name,int _price,String _author){ super(_name,_price,_author); } //覆写X价格 @Override public int getPrice(){ //原价 int selfPrice = super.getPrice(); int offPrice=0; if(selfPrice>4000){ //原价大于40元,则打9折 offPrice = selfPrice * 90 /100; }else{ offPrice = selfPrice * 80 /100; } return offPrice; } }

 

* * *

 

很简单,仅仅覆写了getPrice方法,通过扩展完成了新增加的业务。书店类BookStore需要依赖子类,代码稍作修改,如代码清单6-5所示。

代码清单6-5 书店打折X类

 

王大虎
王大虎

 

public class BookStore { private final static ArrayList<IBook> bookList = new ArrayList<IBook>(); //static静态模块初始化数据,实际项目中一般是由持久层完成 static{ bookList.add(new OffNovelBook(“天龙八部”,3200,”金庸”)); bookList.add(new OffNovelBook(“巴黎圣母院”,5600,”雨果”)); bookList.add(new OffNovelBook(“悲惨世界”,3500,”雨果”)); bookList.add(new OffNovelBook(“X”,4300,”兰陵笑笑生”)); } //模拟书店买书 public static void main(String[] args) { NumberFormat formatter = NumberFormat.getCurrencyInstance(); formatter.setMaximumFractionDigits(2); System.out.println(“———–书店卖出去的书籍记录如下:———–“); for(IBook book:bookList){ System.out.println(“书籍名称:” + book.getName()+”\t书籍作者:” + book.getAuthor()+ “\t书籍价格:” + formatter.format (book.getPrice()/100.0)+”元”); } } }

 

王大虎

 

我们只修改了粗体部分,其他的部分没有任何改动,运行结果如下所示。

 

* * *

 

————书店买出去的书籍记录如下:——————— 书籍名称:天龙八部 书籍作者:金庸 书籍价格:¥25.60元 书籍名称:巴黎圣母院 书籍作者:雨果 书籍价格:¥50.40元 书籍名称:悲惨世界 书籍作者:雨果 书籍价格:¥28.00元 书籍名称:X 书籍作者:兰陵笑笑生 书籍价格:¥38.70元

 

* * *

 

OK,打折X开发完成了。看到这里,各位可能有想法了:增加了一个OffNoveBook类后,你的业务逻辑还是修改了,你修改了static静态模块区域。这部分确实修改了,该部分属于高层次的模块,是由持久层产生的,在业务规则改变的情况下高层模块必须有部分改变以适应新业务,改变要尽量地少,防止变化风险的扩散。

注意 开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。

我们可以把变化归纳为以下三种类型:

·逻辑变化

只变化一个逻辑,而不涉及其他模块,比如原有的一个算法是a*b+c,现在需要修改为a*b*c,可以通过修改原有类中的方法的方式来完成,前提条件是所有依赖或关联类都按照相同的逻辑处理。

·子模块变化

王大虎

一个模块变化,会对其他的模块产生影响,特别是一个低层次的模块变化必然引起高层模块的变化,因此在通过扩展完成变化时,高层次的模块修改是必然的,刚刚的书籍打折处理就是类似的处理模块,该部分的变化甚至会引起界面的变化。

·可见视图变化

可见视图是提供给客户使用的界面,如JSP程序、Swing界面等,该部分的变化一般会引起X反应(特别是在国内做项目,做欧美的外包项目一般不会影响太大)。如果仅仅是界面上按钮、文字的重新排布倒是简单,最司空见惯的是业务耦合变化,什么意思呢?一个展示数据的列表,按照原有的需求是6列,突然有一天要增加1列,而且这一列要跨N张表,处理M个逻辑才能展现出来,这样的变化是比较恐怖的,但还是可以通过扩展来完成变化,这就要看我们原有的设计是否灵活。

王大虎

我们再来回顾一下书店X书籍的程序,首先是我们有一个还算灵活的设计(不灵活是什么样子?BookStore中所有使用到IBook的地方全部修改为实现类,然后再扩展一个ComputerBook书籍,你就知道什么是不灵活了);然后有一个需求变化,我们通过扩展一个子类拥抱了变化;最后把子类投入运行环境中,新逻辑正式投产。通过分析,我们发现并没有修改原有的模块代码,IBook接口没有改变,NovelBook类没有改变,这属于已有的业务代码,我们保持了历史的纯洁性。放弃修改历史的想法吧,一个项目的基本路径应该是这样的:项目开发、重构、测试、投产、运维,其中的重构可以对原有的设计和代码进行修改,运维尽量减少对原有代码的修改,保持历史代码的纯洁性,提高系统的稳定性。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注