1988年,勃兰特·梅耶(Bertrand Meyer)在他的著作《面向对象软件构造(Object Oriented Software
Construction)》中提出了开闭原则,它的原文是这样:“Software entities should be open for extension,but closed for modification”。翻译过来就是:“软件实体应当对扩展开放,对修改关闭”。这句话说得略微有点专业,我们把它讲得更通俗一点,也就是:软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,引入新功能。开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。
----百度百科
为什么没有说是面向对象6大原则,为什么没有将开闭原则包括进去?
开闭原则是最基础的一个原则,前面5个原则就是它的具体形态,开闭原则才是他们的接口。
IBook作为一个接口,里面有三个方法,而小说NovelBook是一个具体的实现类,是所有小说的总称,BookStore指的是书店。
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 autor; public NovelBook(String name,int price,String autor){ this.name=name; this.price=price; this.autor=autor; } public String getAuthor() { return this.autor; } public String getName() { return this.name; } public int getPrice() { return this.price; } }
public class Store { private final static ArrayList<IBook> booklist = new ArrayList<IBook>(); static { // 静态模块加载数据,实际项目一般由持久层完成 booklist.add(new NovelBook("巴黎圣母院", 3200, "雨果")); booklist.add(new NovelBook("悲惨世界", 5600, "雨果")); booklist.add(new NovelBook("天龙八部", 4800, "金庸")); booklist.add(new NovelBook("挪威的森林", 2200, "村上春树")); } public static void main(String[] args) { NumberFormat format = NumberFormat.getCurrencyInstance(); format.setMaximumFractionDigits(2); System.out.println("-------------书店卖出去的书籍记录如下---------------"); for (IBook book : booklist) { System.out.println("书籍名称:" + book.getName() + "\t书籍作者:" + book.getAuthor() + "\t书籍价格:" + format.format(book.getPrice() / 100.0) + "元"); } } }
让程序猿最害怕的需求变化来了: 因为俺们村最近炒股,都赔了,书卖不出去,需要打折来促销,40块以上的9折,以下的8折。
思考如何修改:
1.一了百了,修改接口,如果这个需求变化在设计的时候就想到了就好了。这样修改的话下面的NovelBook类要改,书店类也要改。接口对外是承诺,一旦确认不能修改。不能经常变化。否定!
2.修改NovelBook中的getPrice方法,替换class文件,这个可行。但是还要结合实际情况。待定!
3.扩展一个子类,重写getPrice方法。 可以!
public class OffNovelBook extends NovelBook { public OffNovelBook(String name, int price, String autor) { super(name, price, autor); } @Override public int getPrice() { int price=super.getPrice(); int oprice=0; if(price>4000){ oprice= price*90/100; }else{ oprice= price*80/100; } return oprice; } }
static { // 静态模块加载数据,实际项目一般由持久层完成 booklist.add(new NovelBook("巴黎圣母院", 3200, "雨果")); booklist.add(new NovelBook("悲惨世界", 5600, "雨果")); booklist.add(new NovelBook("天龙八部", 4800, "金庸")); booklist.add(new NovelBook("挪威的森林", 2200, "村上春树")); booklist.add(new OffNovelBook("唐诗三百首", 4500, "谁写的")); }
也许有人会认为高层业务代码已经修改了,但是这是不可避免的,有的时候甚至会连界面也会修改的。 变化也许是逻辑变化,也许是子模块变化,那么相应的对于其他模块必然会造成影响,视图变化也需要扩展。
再说了,如果你修改了以前写好的代码,要知道,在实际开发中,投入的代码都是经过测试MM的千锤百炼的,如果你这一改,测试MM的笑脸你是别想再看到了。不改的话我们还是好朋友。
开闭原则的好处:
1.测试
2.复用性
3.可维护性
总之一句话,拥抱变化,拒绝修改,提倡扩展。系统的稳定性得到了保证。
让程序猿最害怕的需求又变化来了: 现在俺们村文化程度提高了,书店需要扩展,前几天张家的儿子和李家的女儿都考上了计算机专业,一个是大数据,一个是嵌入式,我们要加这俩个领域的书
。
如何思考: 需要增加一个属性领域,还得在原来的基础上扩展,不能修改原有的抽象层,那么我再加一个不就行了吗? 让IComputer接口继承IBook接口,然后再写具体类。通过构造传参。
public interface IComputerBook extends IBook { public String getScope(); }
public class ComputerBook implements IComputerBook { private String name; private int price; private String autor; private String scope; public ComputerBook(String name, int price, String autor, String scope) { this.name = name; this.price = price; this.autor = autor; this.scope = scope; } public String getScope() { return this.scope; } public String getAuthor() { return this.autor; } public String getName() { return this.name; } public int getPrice() { return this.price; } }
static { // 静态模块加载数据,实际项目一般由持久层完成 booklist.add(new NovelBook("巴黎圣母院", 3200, "雨果")); booklist.add(new NovelBook("悲惨世界", 5600, "雨果")); booklist.add(new NovelBook("天龙八部", 4800, "金庸")); booklist.add(new NovelBook("挪威的森林", 2200, "村上春树")); booklist.add(new OffNovelBook("下架的书", 4500, "谁写的")); booklist.add(new ComputerBook("大数据入门", 8500, "李老师", "大数据")); booklist.add(new ComputerBook("嵌入式精髓", 2600, "吴老师", "嵌入式")); }
这样的设计遵循抽象约束原则: 1.通过抽象层约束扩展,对扩展进行边界限定。
2.参数类型,引用对象尽量使用接口或者抽象类。
3.抽象层始终维持稳定,一旦确定不再修改。
1.抽象约束
2.元数据控制模板
元数据: 配置参数,变化的参数,例如登录时需要先检查IP地址,然后决定是否登录,SSH使用了拦截器,这在之前的博客有写过。控制反转,使用底层的反射来写的。
3.制定项目章程
所有成员必须遵守的约定,整齐划一,提高开发效率,这个目前只能是模拟幻想而已。。。
4.封装变化
(1).将相同的变化封装到一个接口或抽象类中。 (2).将不同的变化封装到不同的接口或者抽象类中。
参考书籍《设计模式之禅》
我是菜鸟,我在路上。
版权声明:本文为博主原创文章,未经博主允许不得转载。