文章目录
设计模式(Gof)六大原则之一开闭原则
开闭原则:Open Closed Principle,OCP
开闭原则的定义
开闭原则由勃兰特·梅耶(Bertrand Meyer)提出,他在 1988 年的著作《面向对象软件构造》(Object Oriented Software Construction)中提出:软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification),这就是开闭原则的经典定义。简单点说就是是:一个软件实体应 该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。那么什么是软件实体呢?
这里的软件实体包括以下几个部分:
- 项目中划分出的模块
- 类与接口
- 方法
一个软件产品在她的生命周期内一般都会发生变化,开闭原则视为软件实体的未来事件而制定的对现行开发设计进 行约束的一个原则。
举个例子:以书店销售书籍为例:
public interface Book {
String getName();
int getPrice();
String getAuthor();
}
public class NovelBook implements Book{
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() {
return this.name;
}
@Override
public int getPrice() {
return this.price;
}
@Override
public String getAuthor() {
return this.author;
}
}
public class Store {
static List<Book> bookList = new ArrayList<>();
static {
bookList.add(new NovelBook("红楼梦", 9900, "曹雪芹 "));
bookList.add(new NovelBook("侠客行", 8900, "金庸 "));
bookList.add(new NovelBook("斗破苍穹", 6900, "天蚕土豆"));
bookList.add(new NovelBook("斗罗大陆", 10000, "唐家三少"));
}
public static void main(String[] args) {
//按打折后的价格买书
System.out.println("书店买书记录如下:");
for (Book book : bookList) {
System.out.println("书籍名称:" + book.getName() + "\t\t作者:" + book.getAuthor() + "\t\t价 格:" + book.getPrice() / 100.0 + "元");
}
}
}
项目上线,书籍能正常销售了。但是现在双十一要到了,书店决定要来一波促销活动,70元以上的书籍8折销售, 70元以下的书籍9折销售。对该项目来说,这就是一个变化,我们该怎么应该如下变化呢?有3中解决方法:
(1)修改接口
在IBook接口里新增getOffPrice()方法,专门用于进行打折,所有的实现类都实现该方法。但这样修改的后果就 是,实现类NovelBook要修改,书店类BookStore中的main方法也要修改,同时,IBook作为接口应该是稳定且可 靠的,不应该经常发生变化,因此,该方案被否定。
(2)修改实现类
修改NovelBook类中的方法,直接在getPrice()方法中实现打折处理,这个方法可以是可以,但如果采购书籍的人 员要看价格怎么办,由于该方法已经进行了打折处理,因此采购人员看到的也是打折后的价格,会因信息不对称出 现决策失误的情况。因此,该方案也不是一个最优的方案
(3)通过扩展实现变化
增加一个子类OffNovelBook,覆写getPrice方法,高层次的模块(也就是BookStore中static静态块中)通过 OffNovelBook类产生新的对象,完成业务变化对系统的最小开发。这样修改也少,风险也小。
public class discontNovelBook extends NovelBook {
public discontNovelBook(String name, int price, String author) {
super(name, price, author);
}
@Override
public int getPrice() {
int prePrice = super.getPrice();
if (prePrice > 7000){
return prePrice*80/100;
}else {
return prePrice*90/100;
}
}
}
public class Store {
static List<Book> bookList = new ArrayList<>();
static {
bookList.add(new discontNovelBook("红楼梦", 9900, "曹雪芹 "));
bookList.add(new discontNovelBook("侠客行", 8900, "金庸 "));
bookList.add(new discontNovelBook("斗破苍穹", 6900, "天蚕土豆"));
bookList.add(new discontNovelBook("斗罗大陆", 10000, "唐家三少"));
}
public static void main(String[] args) {
//按打折后的价格买书
System.out.println("书店买书记录如下:");
for (Book book : bookList) {
System.out.println("书籍名称:" + book.getName() + "\t\t作者:" + book.getAuthor() + "\t\t价 格:" + book.getPrice() / 100.0 + "元");
}
}
}
开闭原则的作用
开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。 具体来说,其作用如下。
1. 对软件测试的影响
软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。
2. 可以提高代码的可复用性
粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性
3.可以提高软件的可维护性
遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。