什么是开闭原则?
开放封闭原则称为OCP原则(Open Closed Principle)是所有面向对象原则的核心。
“开闭原则”是面向对象编程中最基础和最重要的设计原则之一。
软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的。
为什么要用开闭原则?
如果在进行功能扩展的时候,添加额外的类是没问题的,但因为功能扩展而修改之前运行正常的程序,这是忌讳的,不被允许的。因为一旦修改之前运行正常的程序,就会导致项目整体要进行全方位的重新测试。这是相当麻烦的过程。导致问题的主要原因是:代码和代码之间的耦合度太高。
先来看开闭原则的定义:
这也是开放封闭原则的核心思想:对扩展开放,对修改封闭.
这是什么含义呢?
- 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况,也就是指我们系统中的模块、类、方法对它们的提供者(开发者)应该是开放的,提供者可以对系统进行扩展(新增)新的功能。
- 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对已有代码进行任何修改,也就是指系统中的模块、类、方法对它们的使用者(调用者)应该是关闭的。使用者使用这些功能时,不会因为提供方新增了功能而导致使用者(调用者)也进行相应修改。
如何实现开放封闭原则呢?
“需求总是变化”、“世界上没有一个软件是不变的”。这里投射出的意思是:需求总是变化的, 可是对于软件设计者来说, 如何才能做到不对原有系统修改的前提下, 实现灵活的扩展. 这就是开闭原则要实现的.
我们在设计系统的时候, 不可能设想一次性把需求确定后, 后面就不改变了.这不科学也不现实的. 既然需求是一定会变化的, 那么我们要如何优雅的面对这种变化呢? 如何设计可以使软件相对容易修改, 不至于需求一变, 就要把整个程序推到重来?
依赖与抽象
实现开放封闭的核心思想就是面对抽象编程,而不是面对具体编程,因为抽象相对稳定。 让类依赖于固定的抽象,所以对修改是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。这是实施开放封闭原则的基本思路。
如何落地开闭原则
如果当前的设计不符合开放封闭原则,则必须进行重构。常用的设计模式主要有模板方法(Template Method)设计模式和策略(Strategy)设计模式。而封装变化,是实现这一原则的重要手段,将经常发生变化的部分封装为一个类。
开闭原则的重要性
开闭原则是最基础的一个原则,其他五个原则都是它的具体形态。开闭原则是其精神领袖,其他五个原则是指导设计的工具和方法。
如何使用开闭原则
注意事项
开闭原则对扩展开放,对修改关闭,并不意味这不做任何修改,低层模块的的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。
变化可以归纳为3种:
案例1:Windows 的桌面主题设计。
分析:Windows 的主题是桌面背景图片、窗口颜色和声音等元素的组合。用户可以根据自己的喜爱更换自己的桌面主题,也可以从网上下载新的主题。这些主题有共同的特点,可以为其定义一个抽象类(Abstract Subject),而每个具体的主题(Specific Subject)是其子类。用户窗体可以根据需要选择或者增加新的主题,而不需要修改原代码,所以它是满足开闭原则的,其类图如图 所示。
案例2:比如现在国庆节,搞图书打折活动,有以下几种做法:
1.新增打折接口
2.修改原油NewBook类
3.新增打折书籍类
按照开放扩展关闭修改原则,应该是第三种方案,这样原有代码不会受到修改。
//书籍接口
public interface IBook {
String getBookName();
String getAuthor();
int getPrice();
}
//书籍类
public class NewBook implements IBook {
private String bookName;
private String author;
private int price;
public NewBook(String bookName, String author, int price){
this.bookName = bookName;
this.author = author;
this.price = price;
}
@Override
public String getBookName() {
return this.bookName;
}
@Override
public String getAuthor() {
return this.author;
}
@Override
public int getPrice() {
return this.price;
}
}
//打折书籍类
public class OffBook extends NewBook {
public OffBook(String bookName, String author, int price) {
super(bookName, author, price);
}
public Double getPrice2(){
return this.getPrice()*0.7;
}
}