【转自】itpub http://tech.it168.com/a2009/0727/612/000000612707.shtml
开闭原则是设计原则基础的基础,其它原则均围绕开闭原则进行展开。开闭原则也就是一个软件实体应当对扩展开放,但对修改关闭。满足了开闭原则的设计,我们的系统将达到在设计稳定的基础上,方便的对软件进行扩展,插入新的功能模块的目的。
怎么样做的开闭原则呢?抽象化是关键,也是我们经常听到的“面象接口编程”,具体一点就是声明的变量的类型、函数的参数类型、函数的返回类型等要尽量使用抽象类和接口。开闭原则实际也是“对可变性的封装原则”,那就是“考虑你的设计中什么可能发生变化,找到一个系统的可变因素,将它封装起来”。把变化封闭起来也就是我们经常用到的继承,编写一个抽象类用子类来继承他,或者编写一个接口让子类去实现他。继承固然很好,既封装了变化又实现了复用,但却不能滥用,也就是说应当把继承仅仅当做封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象。就如我们为了复用一个类里面的函数,便用另一个毫不相干的类来继承此类,这样的继承真可谓不伦不类。更糟糕一些那便是为复用而复用,编写一个抽象类去继承一个毫不相干的另一个抽象类(这样做可能是想复用此类中封装的变化),这样便把多于一种的可变性混合在了一起,混合的结果便是最终让我们思维混乱。
开头我们说开闭原则是设计原则基础的基础,因为其它的设计原则可以作为实现开闭原则的手段和工具。
1、里氏代换原则:任何基类可以出现的地方,子类一定可以出现。
我们知道,实现开闭原则的关键是抽象化,而里氏代换原则中的基类和子类的继承关系正是抽象化的具体体现,所以里氏代换原则是对实现抽象化的具体步骤的规范。违反里氏代换原则一个最经典的例子便是把正方形设计成长方形的子类。
2、依赖倒转原则:要依赖于抽象,不要依赖于实现。说的白一点就是要依赖于抽象类和接口不要依赖具体类,具体类也就是我们可以用new关键字实例化的类。依赖倒转原则是实现开闭原则的一个手段。
3、合成/聚合复用原则:要尽量使用合成/聚合,而不是继承关系达到复用的目的。就如我们前面说的,如果为了复用,便使用继承的方式将两个不相干的类联系在一起,这样的方式是违反合成/聚合复用原则的,更进一步的后果那便是违反里氏代换原则。合成/聚合复用和里氏代换原则相辅相成,合成/聚合复用原则要求我们在复用时首先考虑合成/聚合关系,而里氏代换原则是要求我们在使用继承时,必须满足一定的条件。
4、接口隔离原则:应当为客户端提供尽可能小的单独接口,而不要提供大的总接口。
5、迪米特法则:一个软件实体应当尽可能少的与其他实体发生相互作用。
一个和其它实体关系很少的实体,在系统扩展时受的影响就会很小。当然接口隔离原则也是同样的道理,小的单独的接口,在系统扩展时受到的影响也会很小,所不同的是,迪米特法则(广义迪米特)限制的是相互作用的深度和广度,而接口隔离原则限制的只是相互作用的广度
在网上看到“板桥里人”的一篇文章《你还在用ifelse吗?》他在最后总结里说:“将ifelse用在小地方还可以,如简单的数值判断。但是如果按照你的传统习惯思维,在实现业务功能时也使用ifelse,那么说明你的思维可能需要重塑,你的编程经验越丰富,传统过程思维模式就容易根深蒂固,想靠自己改变很困难;建议接受专业头脑风暴训练。”此文通篇是如何用设计模式来替换ifelse语句的说词,不知道他这种极端的为了设计模式而设计模式的做法,是不是被他所谓的“头脑风暴”给刮疯癫所导致的。我也说一下我极端的想法,如果一个极端到没有任何可扩展性要求的系统,用面向对象的语言开发面向过程的程序,并无不可,面向对象里面的类只不过是我们分类存放函数的一个容器,其他别无用处,如果这时你还要写一大堆的接口和抽象类来显摆你所了解的设计模式,这简直就是强 奸了设计模式,因为设计模式是为方便的扩展系统而生的,并不是让你拿来显摆的。关于各种对“将条件转移语句改写成为多态性”的代码重构做法的看法,我更倾向阎宏的的看法。
上而讲的“将条件转移语句改写成为多态性”的代码重构的做法有两大缺点。
第一大缺点,任何语言都提供条件转移功能,如果抛弃语言本身的一些功能,那么语言存在的价值又能体现在哪里呢?难道一个面向对象的语言,面向对象的特性就是这个语言的全部吗?条件转移本身并不是错误的,也不是什么罪恶,他更不是某些人眼里面向过程语言向面向对象语言过渡时一个权宜的保留。如果需要,设计师完全可以选择使用条件转移ifelse,并且不需要去接受什么头脑风暴的摧残。
第二大缺点,使用多态性代替条件转移意味着大量的类被创建出来。比如一个类如果有三个方法,每个方法都有一个三段的条件转移语句,如果将它们都用多态性代替的话,就会造出九个不同的类。很难想象设计师怎么能明白这九种组合成员之间的关系。
那么何时需要用多态性取代条件转移语句呢?
应当从“开闭”原则出发来做判断。如果一个条件转移语句确实封装了某种业务逻辑的可变性,那么将此种可变性封装起来就符合“开闭”原则的设计思想。但是,如果一个条件转移语句没有涉及重要的业务逻辑,或者不会随着时间的变化而变化,也不意味着任何的可扩展性,那么它就没有涉及任何有意义的可变性。这时候将这个条件转移语句改写成为多态性就是一种没有意义的浪费。阎宏将这种对多态性的滥用叫做“多态性污染”。如果再滥用一些设计模式,估计就应该叫“设计模式污染”了。
分享到:
相关推荐
设计模式6大原则:开闭原则
JAVA设计模式之设计原则 ---开闭原则源码
C# 版本,OCP原则的Demo,内部培训资料。
开闭原则指的是一个软件实体应对对扩展开发,对修改关闭(Software entities should be open for extension, but closed for modification)。这个原则是说在设计一个模块的时候,应对使这个模块可以在不被修改的前提...
开闭原则是一种设计思想,并不局限于java语言
开闭原则.rar开闭原则.rar开闭原则.rar之java设计模式
Java Web设计模式之OCP(开闭原则) 如有疑问,请留言!
面向对象设计原则:面向对象设计原则、开闭原则、里氏替换原则、里氏替换原则、里氏替换原则
python开闭原则 开闭原则是面向对象设计中的一个重要原则,它指出一个软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着当需要添加新功能时,应该通过扩展现有代码来实现,而不是修改已有代码。...
面向对象的设计原则 单一职责原则 开闭原则 里氏替换原则 依赖倒置原则 接口分离原则 迪米特法则 合成复用原则
面向对象设计原则概述 单一职责 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 迪米特法则
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能...
软件体系结构七大设计原则,开闭原则 里氏代换原则 依赖倒转原则 迪米特法则 迪米特法则
1、开闭原则 2、里氏代换原则 3、依赖转换原则 4、接口隔离原则 5、合成/聚合复用原则 6、最少知识原则 (二)设计模式 1)工厂模式(Factory) 2)抽象工厂模式(Abstract Factory) 3)建造者模式(Builder) 4)...
c# 设计模式 开放封闭原则
从招式与内功谈起——设计模式概述(一) 从招式与内功谈起——设计模式概述(二) 从招式与内功谈起——设计模式概述(三) 面向对象设计原则 面向对象设计原则之单一职责原则 面向对象设计原则之开闭原则 ...
详细介绍了设计模式六大原则,配有示例代码和图片,有开闭原则,单一职责原则,里氏替换原则,依赖倒置原则,接口隔离原则,迪米特法则等等。
面向对象设计原则,开闭原则,迪米特法则,里氏代换,接口隔离
面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 迪米特法则
软件设计的开闭原则:如何不修改代码却能实现需求变更