锁定老帖子 主题:对于OCP原则的困惑
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-09-22
to:yhc0125
他们前面也给了你不少方法了,你比较一下,哪一种方法的代码编写量最小? 我看啊,还是: A temp = new B();; | v A temp = new C();; 这样最省事,只用改一个字母。:P gigix 写道 在一个reasonable的架构下,没有任何client代码会直接去new一个对象。
这样绝对的话,我是不说的。 |
|
返回顶楼 | |
发表时间:2004-09-22
yhc0125 写道 比如说我定义了一个接口Interface A,他的一个实现class B,我在调用B来完成功能时这样做A temp = new B(); 这样的话当我给他另外一个实现class C时,我的客户段代码还是要改变的: A temp = new C(); 完全不变是不可能的,但变化所影响的范围可以得到限制,或者从代码中分离出来。 想想你用过的jdbc,你的驱动改变的时候,客户端代码需要改变吗? 你可以了解一下bridge pattern 是如何把抽象与实现相分离的。 当然还有适度问题,像庄所说的,不必做无用功,如果不需要实行这种抽象与实现的分离或意义不大,完全不必去费力气实现。 |
|
返回顶楼 | |
发表时间:2004-09-22
没有什么纯粹的架构合理这样的指标。
一个架构是否合理,只能是相对于需求,以及需求的变动而言的。 面对N个需求,以及随后的M种需求变更,你的代码是不是最节省的?这就是判断标准。 不要用一个系统中interface的数量来判断设计的好坏。 也不要用一个系统中工厂的数量来判断设计的好坏。 也不要用一个系统中XML配置文件的数量来判断设计的好坏。 也不要用一个系统中IOC的次数来判断设计的好坏。 也不要用一个系统中AOP的次数来判断设计的好坏。 这些都是静态的,而不是动态的指标。 |
|
返回顶楼 | |
发表时间:2004-09-22
只要使用了继承,出现了派生类,OCP原则都会被打破,无论你如何部署代码,显式创建派生类的代码都是无可避免的。
如果你一定要坚持OCP原则,首先必须坚持CARP原则,只有CARP原则成立的情况下才能达到OCP的效果。 |
|
返回顶楼 | |
发表时间:2004-09-22
OCP作为OO最基本的原理,是有它存在的意义的。
当你在你的构架的核心代码B里写下: A a=new A(); 这样一行代码时,你就应该百倍小心,甚至觉得写下这一句代码很“不可思议”, 如果B 和 A 在不同的包中,那么你更应该值得重新审视你的设计。 a对你所见的是一个具体类,而不是一个抽象类。 比如说本来: public class A implements AI 接口AI仅仅提供了稳定的method:doA(); 然而在B里,你不仅仅看到了doA();你还看到了A所公开的其自身独有的一些public 方法。等于把这种易变的因素公开给了A的使用者。那么,这一句代码意味着A的变化将是B变化的直接因素。变化波及的范围越大,说明你的设计越是丑陋。 隔离这种具体类之间的关联设计模式都有过相关讨论: 1)工厂隔离 2)配置隔离 我更喜欢第2)种,其实把它提高一点,就是容器隔离的概念。 用容器组装核心类,核心类的配置可以通过更改配置文件来修改。 当然,这些都离不开诸如Constructor这些反射机制。 |
|
返回顶楼 | |
发表时间:2004-09-22
为什么要隔离?
设计为什么就是“丑陋”的? 隔离、美丽,都要付出代价的,这些代价,究竟该不该付出,是需要考虑的。 |
|
返回顶楼 | |
发表时间:2004-09-22
多谢大家对我这个简单问题的关注。
我觉得应该明确的一点是ocp原则是非常重要的,可以给我们的开发带来很大帮助,但根据问题的具体情况来分类处理: 1、简单不变的应用,我可能不会使用ocp原则,而是采取直接实现的方式,就像Bob大叔说的:不要对任何事物都进行抽象 2、一般的应用,使用ocp原则,变化的时候在客户端调用时简单修改一下就好了 3、使用工厂或容器,用他们为客户端创建对象 在Spring里面同样是由一个工厂来生成和管理所有bean的,按照Ioc原则,就是说一次把对象都创建好,用那一个都可以,而不用客户端去创建了,这样是不是客户端只要有一个接口引用就行了? |
|
返回顶楼 | |
发表时间:2004-09-22
庄表伟 写道 为什么要隔离?
设计为什么就是“丑陋”的? 隔离、美丽,都要付出代价的,这些代价,究竟该不该付出,是需要考虑的。 a对你所见的是一个具体类,而不是一个抽象类。 比如说本来: public class A implements AI 接口AI仅仅提供了稳定的method:doA(); 然而在B里,你不仅仅看到了doA();你还看到了A所公开的其自身独有的一些public 方法。等于把这种易变的因素公开给了A的使用者。那么,使用者往往会很自然也很方便的使用了A的一些具体方法,而不是接口的稳定方法。那么,从这个意义上来说,这一句代码意味着A的变化将是B变化的直接因素。变化波及的范围越大,说明你的设计越是丑陋。 A这个具体类所包含太多的变化的咚咚。公开他们,这就是丑陋的。 |
|
返回顶楼 | |
发表时间:2004-09-22
如果你选择了Java,但你却没有选择Java的面向接口。
那么,我还是想说:你没用好Java。 |
|
返回顶楼 | |
发表时间:2004-09-22
to:firebody
我们来说一些概念,比如说,什么叫“用法”。 一个类 ClassA,有n个public函数,还有m个private的函数。对于外界来说:ClassA的用法,就是由那n个public函数来定义的。 当且仅当,ClassA有一个以上的用法: 1、doA(),doB() 2、doA(),doC() 这时,我们才需要定义两个interface:IAB,IAC 然后重构ClassA,使其implements IAB,IAC 然后再利用工厂模式,在需要按IAB方式使用ClassA的地方,返回一个以IAB接口表示的ClassA,在需要按IAC方式使用ClassA的地方,返回一个以IAC接口表示的ClassA。 以这样的方式,使用接口,才是对于java的正确使用。 而如果你的ClassA只有一种用法 doA(),doB(),doC() 而你为了这个唯一的用法,去声明一个interface IABC, 然后再用ClassA implements IABC 然后再用工厂方式,返回一个IABC 你说我们俩,谁没有用好java!? 只有在需求出现之后,你才需要重构你的代码,使之支持两种不同的“用法”。一开始就搞出,类+接口+工厂,这就是典型的过度设计! 最后问你一个问题: 谁告诉你接口就是稳定的?类就是不稳定的? 他们都是java代码,要改一样可以改。 |
|
返回顶楼 | |