我通常强调抽象依赖原则:为了应对需求变化,代码中要尽可能地使用(依赖)抽象类型,而非具体类。而不把开放封闭原则(The Open-Closed Principle 、OCP)作为重点加以介绍,主要是因为开放封闭原则涉及的议题较多,容易引起一些误解。
★Software entities(classes ,modules,functions,,etc.) should be open for extension,but closed formodification.一个软件实体(类、模块、函数等等)应对扩展开放,对修改关闭。
1.对扩展开放
对扩展开放”意味着什么?
1)通常人们讨论Software entities(classes ,modules)这一部分。对于Java中有类A,我们可以方便的创建A的新的子类型SubA,而且子类型SubA可以定义新的(A中没有的)操作。这是OOP中很容易做到的事情,也是A对扩展开放的主要方面。即
- 类A的派生
- SubA的扩展继承
2.对修改关闭
- 接口与实现的分离。既然接口与实现是分离的,对修改关闭当然仅仅要求对接口的修改关闭。所以,我们能够自由地修改其实现。
- 哪些对实现的修改,涉及到接口?典型的例子是分支结构,
-
public static Door getObject(String typeName) {
//int ID
-
if(typeName.equals(
"D1")){
-
return
new D1();
-
}
else
if(typeName.equals(
"D2")){
-
return
new D2();
-
}
else{
-
return
null;
-
}
-
}
增加新的分支,不会涉及 getObject方法头的修改——但这不意味着方法的接口没有受到影响。对于形参的验证(这里 return null代替了验证)也是用户怎样使用该方法的一部分——方法的接口的一部分。换一种方式说,假定getObject的形参的验证,字符串D1和D2是合法的参数,其他为非法参数;增加新的分支后,字符串D1、D2和D3是合法的参数,这就意味着
方法的前置条件发生了变化,因而接口被修改。
3.封装变化
“需求总是变化”,而封装变化(从类的方面说),OCP仅仅意味着使用一个大概念来涵盖/容纳可能出现的变化。例如你的系统中养猫养狗,那么养动物就涵盖了未来你养乌龟;如果未来你养花,就需要更大的概念...按照设计忠告——父类型通常设计成抽象类型,所以我们直接呈上了依赖抽象类型作为原则。
说到这里,再回想一下前面说的5项原则,恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:
单一职责原则告诉我们实现类要职责单一;
里氏替换原则告诉我们不要破坏继承体系;
依赖倒置原则告诉我们要面向接口编程;
接口隔离原则告诉我们在设计接口的时候要精简单一;
迪米特法则告诉我们要降低耦合。
而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。
最后说明一下如何去遵守这六个原则。对这六个原则的遵守并不是是和否的问题,而是多和少的问题,也就是说,我们一般不会说有没有遵守,而是说遵守程度的多少。任何事都是过犹不及,设计模式的六个设计原则也是一样,制定这六个原则的目的并不是要我们刻板的遵守他们,而需要根据实际情况灵活运用。对他们的遵守程度只要在一个合理的范围内,就算是良好的设计。我们用一幅图来说明一下。
图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。
在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。
转载:
http://blog.csdn.net/zhengzhb/article/details/7296944
https://blog.csdn.net/yqj2065/article/details/53508056