论坛首页 Java企业应用论坛

敏捷思考 遵循与破坏"开闭原则"

浏览 12950 次
精华帖 (1) :: 良好帖 (1) :: 新手帖 (18) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-09-08   最后修改:2011-03-14
OO

开闭原则的定义

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原则是必然的.

   发表时间:2009-09-08   最后修改:2009-09-08
哦。亲爱的  solonote  对于这情况,你为什么不一开始的时候就使用工厂方法模式呢?

问题总有局限性的,我们需要关注的是一个整体,如果你一开始就想到这个问题,那么就不会出现这种尴尬了
0 请登录后投票
   发表时间:2009-09-08   最后修改:2009-09-08
kysdvnm 写道
哦。亲爱的  solonote  对于这情况,你为什么不一开始的时候就使用工厂方法模式呢?

问题总有局限性的,我们需要关注的是一个整体,如果你一开始就想到这个问题,那么就不会出现这种尴尬了



Why Factory Method?我实在看不出这个场景和工厂方法有什么关系,什么东西需要被制造出来呢? 你指的整体是什么?
0 请登录后投票
   发表时间:2009-09-08  
敏捷本质上跟开闭原则就是冲突的
0 请登录后投票
   发表时间:2009-09-08  
敏捷只是一种价值观与一些开发的建议,和OCP怎么会有冲突呢?
0 请登录后投票
   发表时间:2009-09-15  
OCP是理想设计原则,没有绝对的对修改关闭的
0 请登录后投票
   发表时间:2009-09-15   最后修改:2009-09-15
引用
IUserDAO方案:
1.我要做更多的工作,如果以后没有两种以上的实现,这个接口将毫无意义.
2.如果接口不稳定,比如要增加一个读取用户的操作,那么我们必须修改IUserDAO与UserDAO两个地方,增加了额外的工作量.
3.增加了程序的复杂度.
这个方案如果以后没有需求变化,将给系统带来无用的设计以及更多的维护成本.

1.如果没有需求变更,这个前题本身就是银弹?
2.如果连接口我们都不能相信的话,我们能相信谁呢?(很想电影台词?)
接口是人类思考行为的一种抽象.而不是对代码行为的抽象.....(如果你不以这个为出发点设计接口那么变更是必然的)
1 请登录后投票
   发表时间:2009-09-16   最后修改:2009-09-16
异常哥 写道

接口是人类思考行为的一种抽象.而不是对代码行为的抽象.....(如果你不以这个为出发点设计接口那么变更是必然的) 同意


1.很多情况下我们只会用一种ORM实现,在这种情况下去做抽象本身是无意义的.
2.不单单只有接口可以隔离实现,每一个函数也可以作为一种抽象,隔离了具体的实现,人类思考行为的抽象一定要是接口吗?
3.引入接口必定造成更多的维护成本,如果没有两种以上的实现,这是毫无意义的.
4.我们只能相信接口吗?
5.没有需求变化不是银弹而是判断,判断抽象的价值,判断需求变化的可能性,考虑项目本身的目标,是一个框架,还是仅仅是一个应用,引入抽象就意味着更多的维护成本,因此必须警惕

石中玉 写道
OCP是理想设计原则,没有绝对的对修改关闭的


OCP不是理想,是很实际的设计原则,我觉得OCP原则是用来检验之前的设计是否合理的一种标准.比如那个例子"我们现在有两种DAO的实现需要,那么增加第三种的时候,应当是遵循OCP原则的,如果不能遵循,说明原来的设计存在问题".
所以遵循OCP原则进行设计时,考虑的事情是,以后发生了这类变化,应当遵循OCP原则.
0 请登录后投票
   发表时间:2009-09-17  
“半个月后,客户有了新的需求,它们需要将一部分用户对象存储到XML文件.”
这个需求我觉得没必要做接口多实现把自己套死,UserDAOTXTImp和UserDAOXMLImp不是替代关系。
如果仅仅只是存储需求可以不修改原UserDAO的方法,增加saveUserToXml方法。如果涉及更多操作(save/load/query)等,可以另建一个XmlUserDAO类。

赞同楼主对提前设计的看法。
0 请登录后投票
   发表时间: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

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics