锁定老帖子 主题:敏捷思考 遵循与破坏"开闭原则"
精华帖 (1) :: 良好帖 (1) :: 新手帖 (18) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-09-08
最后修改:2011-03-14
开闭原则的定义 Software entities should be open for extension, but closed for modification. 软件实体应该对扩展是开放的,但是对于修改应当是关闭的.凡是定义一般都是很晦涩的,那么下面举一个应用场景来说明开闭原则的价值.
第一天,客户提出一个需求,我们需要将用户对象存储到文件的UserDAO. 解决方案:
public class UserDAO{ public void saveUser(User user) { //将一个用户对象存储到文件. } } 半个月后,客户有了新的需求,它们需要将一部分用户对象存储到XML文件. 方案1(破坏OCP原则): public class UserDAO { public void saveUser(User user, String saveMethod) { if (saveMethod.equals("txt")) { // 将一个用户对象存储到文本文件. } else if (saveMethod.equals("xml")) { // 将一个用户对象存储到xml文件. } } } 这个方案带来的变化: 1.我要修改依赖UserDAO的类,让其多传入一个参数saveMethod 2.我要维护if...else判断的正确性,如果传入的字符不是txt和xml,那么我还要进行异常处理. 3.加入存储到xml的代码后我无法预知对原来存储到txt的功能是否造成了影响. 4.如果需求再一次变化,那么我必须继续修改saveUser方法,甚至可能因为需要更多的参数而修改了依赖UserDAO的类.
方案2(遵循OCP原则): public interface IUserDAO { public void saveUser(User user); } public class UserDAOTXTImp implements IUserDAO { public void saveUser(User user) { //存储到txt } } public class UserDAOXMLImp implements IUserDAO { public void saveUser(User user) { //存储到xml } } 这个方案带来的变化: 1.我要修改依赖UserDAO的类,让其依赖IUserDAO接口. 2.我重新实现一个存储到xml的UserDAO. 3.即使需求发生变化,需要存储到数据库的,我只需要重新实现IUserDAO接口. 4.这样的修改不会破坏原有程序.
以上看来是一个标准的OCP原则教程,那么下面我们进行进一步的思考:
来看看我们破坏了几次OCP原则. 第一天的开发,没有破坏OCP原则,我们只是单纯的增加了一个新功能. 半个月后的开发,无论我们采用方案一还是方案二我们都破坏了OCP原则. 如果我们使用方案一,在以后的变化中我们就会继续破坏OCP原则,并且带来很多负面的影响.
如果我在第一天就采用IUserDAO,整个过程都不会破坏OCP原则,听起来很不错. 那么我来对比一下第一天就采用IUserDAO所带来的不同:
IUserDAO方案: 1.我要做更多的工作,如果以后没有两种以上的实现,这个接口将毫无意义. 2.如果接口不稳定,比如要增加一个读取用户的操作,那么我们必须修改IUserDAO与UserDAO两个地方,增加了额外的工作量. 3.增加了程序的复杂度. 这个方案如果以后没有需求变化,将给系统带来无用的设计以及更多的维护成本.
UserDAO方案: 1.即使有了需求变化,要抽取出一个借口也是非常方便的,相对于IUserDAO方案并没有多出太多的工作量. 2.使用UserDAO方案破坏了OCP原则,破坏了DIP原则,没有依赖于抽象而依赖于具体实现.但是,我们一定要遵循这些原则吗? 3.程序简单直接,易维护.
我无法预期半个月后的那次需求变动,因此我不应该做提前的设计.
我对OpenClose原则的解释: 你对一类问题需要 一个以上的解决方案, 那么当加入新的解决方案时,你的修改不应该对已有模块产生影响,而你可以通过对抽象的实现来进行扩展. OpenClose原则对于此外的场景是无意义的,比如你要加入一个新功能,IUserDAO现在需要读取用户的方法,你肯定要打开IUserDAO进行修改,这个时候破坏OpenClose原则是必然的. 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-09-08
最后修改:2009-09-08
哦。亲爱的 solonote 对于这情况,你为什么不一开始的时候就使用工厂方法模式呢?
问题总有局限性的,我们需要关注的是一个整体,如果你一开始就想到这个问题,那么就不会出现这种尴尬了 |
|
返回顶楼 | |
发表时间:2009-09-08
最后修改:2009-09-08
kysdvnm 写道 哦。亲爱的 solonote 对于这情况,你为什么不一开始的时候就使用工厂方法模式呢?
问题总有局限性的,我们需要关注的是一个整体,如果你一开始就想到这个问题,那么就不会出现这种尴尬了 Why Factory Method?我实在看不出这个场景和工厂方法有什么关系,什么东西需要被制造出来呢? 你指的整体是什么? |
|
返回顶楼 | |
发表时间:2009-09-08
敏捷本质上跟开闭原则就是冲突的
|
|
返回顶楼 | |
发表时间:2009-09-08
敏捷只是一种价值观与一些开发的建议,和OCP怎么会有冲突呢?
|
|
返回顶楼 | |
发表时间:2009-09-15
OCP是理想设计原则,没有绝对的对修改关闭的
|
|
返回顶楼 | |
发表时间:2009-09-15
最后修改:2009-09-15
引用 IUserDAO方案:
1.我要做更多的工作,如果以后没有两种以上的实现,这个接口将毫无意义. 2.如果接口不稳定,比如要增加一个读取用户的操作,那么我们必须修改IUserDAO与UserDAO两个地方,增加了额外的工作量. 3.增加了程序的复杂度. 这个方案如果以后没有需求变化,将给系统带来无用的设计以及更多的维护成本. 1.如果没有需求变更,这个前题本身就是银弹? 2.如果连接口我们都不能相信的话,我们能相信谁呢?(很想电影台词?) 接口是人类思考行为的一种抽象.而不是对代码行为的抽象.....(如果你不以这个为出发点设计接口那么变更是必然的) |
|
返回顶楼 | |
发表时间:2009-09-16
最后修改:2009-09-16
异常哥 写道 接口是人类思考行为的一种抽象.而不是对代码行为的抽象.....(如果你不以这个为出发点设计接口那么变更是必然的) 同意 1.很多情况下我们只会用一种ORM实现,在这种情况下去做抽象本身是无意义的. 2.不单单只有接口可以隔离实现,每一个函数也可以作为一种抽象,隔离了具体的实现,人类思考行为的抽象一定要是接口吗? 3.引入接口必定造成更多的维护成本,如果没有两种以上的实现,这是毫无意义的. 4.我们只能相信接口吗? 5.没有需求变化不是银弹而是判断,判断抽象的价值,判断需求变化的可能性,考虑项目本身的目标,是一个框架,还是仅仅是一个应用,引入抽象就意味着更多的维护成本,因此必须警惕 石中玉 写道 OCP是理想设计原则,没有绝对的对修改关闭的
OCP不是理想,是很实际的设计原则,我觉得OCP原则是用来检验之前的设计是否合理的一种标准.比如那个例子"我们现在有两种DAO的实现需要,那么增加第三种的时候,应当是遵循OCP原则的,如果不能遵循,说明原来的设计存在问题". 所以遵循OCP原则进行设计时,考虑的事情是,以后发生了这类变化,应当遵循OCP原则. |
|
返回顶楼 | |
发表时间:2009-09-17
“半个月后,客户有了新的需求,它们需要将一部分用户对象存储到XML文件.”
这个需求我觉得没必要做接口多实现把自己套死,UserDAOTXTImp和UserDAOXMLImp不是替代关系。 如果仅仅只是存储需求可以不修改原UserDAO的方法,增加saveUserToXml方法。如果涉及更多操作(save/load/query)等,可以另建一个XmlUserDAO类。 赞同楼主对提前设计的看法。 |
|
返回顶楼 | |
发表时间:2009-09-17
最后修改:2009-09-17
solonote 写道 异常哥 写道 接口是人类思考行为的一种抽象.而不是对代码行为的抽象.....(如果你不以这个为出发点设计接口那么变更是必然的) 同意 1.很多情况下我们只会用一种ORM实现,在这种情况下去做抽象本身是无意义的. 2.不单单只有接口可以隔离实现,每一个函数也可以作为一种抽象,隔离了具体的实现,人类思考行为的抽象一定要是接口吗? 3.引入接口必定造成更多的维护成本,如果没有两种以上的实现,这是毫无意义的. 4.我们只能相信接口吗? 5.没有需求变化不是银弹而是判断,判断抽象的价值,判断需求变化的可能性,考虑项目本身的目标,是一个框架,还是仅仅是一个应用,引入抽象就意味着更多的维护成本,因此必须警惕 1.本题问题出在XML上 2.在没OO之前,就是用你这种方式抽象的.已经有人用过了. 3.维护成本?代码行数少了,注释密度增大后,人眼一次看到全图的可能性提高了... 4.我可以保证世界上99%以上的应用使用对象不是程序员.所以我相信用户读懂接口可能性更高一些出错可能性小 5.怎么对未来进行判断?你是说算卦么? 6.对于现实与软件有很多理论. 你可以把你的理论延生出的实践拿出来我们来试一下. 好的话二话不说同意你.跟随你. 不好的的话. 你说出天花乱坠我也不会信的. -\com.mimi.dao\ +AbcDAO.java +impl\ +AbcDAOImpl.java |
|
返回顶楼 | |