设计模式笔记(六)设计六大原则之六--开闭原则
2017-11-21 22:45
344 查看
定义
一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。软件实体:
项目或软件产品中按照一定的逻辑规则划分的模块
抽象和类
方法
示例
public interface IBook { //书籍有名称 public String getName(); //书籍有售价 public int getPrice(); //书籍有作者 public String getAuthor(); }
public class NovelBook implements IBook{ //书籍名称 private String name; //书籍价格 private int price; //书籍的作者 private String author; //通过构造函数传递书籍数据 public NovelBook(String _name,int _price,String _author) { this.name = _name; this.price = _price; this.author = _author; } @Override public String getName() { // TODO Auto-generated method stub return this.name; } @Override public int getPrice() { // TODO Auto-generated method stub return this.price; } @Override public String getAuthor() { // TODO Auto-generated method stub return this.author; } }
/** * 书店售书类 * @author Administrator * */ public class BookStore { private final static ArrayList<IBook> bookList = new ArrayList<IBook>(); //static 静态模块初始化,项目中一般是通过持久层完成 static { bookList.add(new NovelBook("天龙八部",3200,"金庸")); bookList.add(new NovelBook("巴黎圣母院",5600,"雨果")); bookList.add(new NovelBook("悲惨世界",3500,"雨果")); bookList.add(new NovelBook("金瓶梅",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)+"元"); } } }
运行结果:
———书店卖出去的书籍记录如下:———–
书籍名称:天龙八部 书籍作者:金庸 书籍价格:¥32.00元
书籍名称:巴黎圣母院 书籍作者:雨果 书籍价格:¥56.00元
书籍名称:悲惨世界 书籍作者:雨果 书籍价格:¥35.00元
书籍名称:金瓶梅 书籍作者:兰陵笑笑生 书籍价格:¥43.00元
此时如果需求变化,希望40元以上的书籍九折销售,其他8折销售,那么我们如何应对呢?
1.修改接口?
如果在IBook上新增一个getOffPrice()的方法,专门用于进行打折处理,这样结果实现类NovelBook要修改,main方法也要修改。而且接口IBook应该是稳定且可靠的,不应该经常发生变化,否则接口作为契约的作用就失去了效能
2.修改实现类?
修改NovelBook类中的方法,直接在getPrice()中实现打折处理,一般项目中经常使用的就是这种方法(缺陷修复),但是如果采购书籍的人员也要看价格呢?那么他看到的就是打折后的价格了,显然也不正确。
3.通过扩展实现变化
增加一个子类OffNovelBook,覆写getPrice方法,完成业务变化对系统的最小化开发。风险小。
public class OffNovelBook extends NovelBook{ public OffNovelBook(String _name, int _price, String _author) { super(_name, _price, _author); // TODO Auto-generated constructor stub } //覆写销售价格 @Override public int getPrice() { //原价 int selfPrice = super.getPrice(); int offPrice = 0; if(selfPrice > 40) { offPrice = selfPrice * 90/100; }else { offPrice = selfPrice * 80/100; } return offPrice; } }
这样业务逻辑只需要修改static块中的构造书籍,其他并没有任何改动。
bookList.add(new OffNovelBook("天龙八部",3200,"金庸")); bookList.add(new OffNovelBook("巴黎圣母院",5600,"雨果")); bookList.add(new OffNovelBook("悲惨世界",3500,"雨果")); bookList.add(new OffNovelBook("金瓶梅",4300,"兰陵笑笑生"));
运行结果显示:
———书店卖出去的书籍记录如下:———–
书籍名称:天龙八部 书籍作者:金庸 书籍价格:¥28.00元
书籍名称:巴黎圣母院 书籍作者:雨果 书籍价格:¥50.00元
书籍名称:悲惨世界 书籍作者:雨果 书籍价格:¥31.00元
书籍名称:金瓶梅 书籍作者:兰陵笑笑生 书籍价格:¥38.00元
总结
逻辑变化
只变化一个逻辑,不涉及其他模块,可以通过修改原有类中的方法来完成,前提条件是所有依赖或关联类都按照相同的逻辑处理。子模块变化
一个模块变化,会对其他模块产生影响,特别是一个低层次的模块变化必然会引起高层模块的变化,因此在通过扩展完成变化时,高层次的模块修改时必然的。可见视图变化
提供给客户使用的视图,如jsp等,该部分变化一般会引起连锁反应。如果一个展示数据列表,现在增加显示一列,这一列要跨很多张表,处理很多逻辑才能展现出来,这样的变化时比较恐怖的。还是可以通过扩展来完成,这要看原有的设计是否灵活。为什么采用开闭原则
测试逻辑清晰
单元测试时只需要保证此新加的类正确就可以了,非常清晰。可以提高复用性
逻辑颗粒度越小,被复用的可能性就越大。提高可维护性
对原有代码修改,要先读懂源码,是一件很痛苦的事情。通过扩展,大大提高了维护人员的可维护性。面向对象开发要求
设计开始就要考虑有可能变化的因素,留下接口,等待可能变为现实。如何使用开闭原则
抽象约束
通过接口或抽象类可以约束一组可能变化的行为,并且能够对扩展开放。比如上面实例中还可以增加艺术书籍,技术书籍,水利工程书籍等等。只需要扩展接口,其他的水到渠成。元数据控制模块行为
元数据:配置参数,可以从文件中获得,也可以从数据库中获得,用来描述环境和数据的数据。比如login方法中提供了这样的逻辑,先检查IP地址是否在允许访问的列表中,然后再决定是否需要到数据库中验证密码。制定项目章程
比如SSH项目开发,bean配置文件非常多,如果扩展,就需要增加子类,并修改配置文件。然而如果制定了一个项目章程,规定所有Bean都自动注入等等。这就需要项目内约束。封装变化
将相同的变化封装到一个接口或抽象类中,将不同的变化封装到不同的接口或抽象类中。相关文章推荐
- 设计模式笔记(一)设计六大原则之一--单一职责原则
- 设计模式笔记(五)设计六大原则之五--迪米特法则
- 设计模式笔记(三)设计六大原则之三--依赖倒置原则
- 设计模式学习笔记:六大原则
- 设计模式学习笔记:六大原则
- 设计模式之禅笔记--面向对象设计六大原则之一
- Android 设计模式 笔记 - 面向对象的六大原则
- 设计模式的六大原则【笔记】
- 设计模式学习笔记(一)六大原则
- 设计模式笔记(二)设计六大原则之二--里氏替换原则
- 设计模式笔记(四)设计六大原则之四--接口隔离原则
- 设计模式之六大设计原则学习笔记
- 设计模式六大原则(4):里氏替换原则
- 设计模式之六大原则——接口隔离原则(ISP)
- 设计模式六大原则(1):单一职责原则
- 设计模式六大原则(转)
- 设计模式六大设计原则之单一职责原则(Single Responsibility Principle)
- 设计模式六大原则——迪米特法则(LoD,Law of Demeter)
- 设计模式六大原则小结
- 设计模式学习之——六大设计原则之二:里氏替换原则