解读设计模式--开闭原则

来源:互联网 发布:微博手游直播软件 编辑:程序博客网 时间:2024/05/16 07:35

认识开闭原则

       开闭原则是面向对象设计中最重要的原则之一,它也是设计模式的核心原则,其他一切原则都是实现开闭的手段。

       开闭原则是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;但对于原有代码的修改是封闭的,即不应该修改原有的代码。

开闭原则由来

      我们在做任何系统的时候,都不要指望系统一开始时需求就确定,就再也不变化,这是不科学的想法,而且需求也一定会变化的,当我们面对需求的变化时候,设计的软件可以相对容易修改,不至于说需求一变推倒重建。

      这样,我们怎样的设计才能面对需求的改变可以保持相对的稳定,从而使得系统可以在第一个版本之后不断更新版本呢?

      这时候开闭原则就应运而生。1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了开闭原则,它的原文是这样:“Software entities should be open for extension,but closed for modification”。翻译过来就是:“软件实体应当对扩展开放,对修改关闭”。

开闭原则的好处

       开闭原则是面向对象的核心所在,遵循这个原则当然可以带来面向对象技术的巨大好处,即可维护性好、可扩展性好、可复用性高、灵活性好。

      因为我们可以利用抽象类和接口来对软件进行扩展,加入新的功能,非常灵活,这样系统就会不断增加新的组件来适应不断变化需求,也就是以变应万变;另外,我们不用去修改原先系统的一些组件,这样软件的稳定性是很高的,当然我们可以进行扩展,所以软件系统也具有一定的延续性。其实这也是可持续发展态度来解决软件问题。

开闭原则在实践中如何体现?

      讲了这么多开闭原则的理论性的东西,可能会有读者问,开闭原则在实践中是如何体现?

      在csdn论坛中看到了这样一个贴子就是问的这个问题,感觉里面有几个回复还是很有说服力的。截图如下

clip_image001

clip_image002

clip_image003

      关于#2楼的回答,应该是从非常理论的层次来说的,这个回答很笼统,机会所有关于开闭原则的问题,用这句话回答都正确。虽然这个回答对楼主的提问没有什么用处,但是对我这篇博客介绍开闭原则还是很有用处的。

      多用抽象类和接口来编程才能很好的体现开闭原则。详细见下面介绍:

      1)多使用抽象类

在设计类时,对于拥有共同功能的相似类进行抽象化处理,将公用的功能部分放到抽象类中,所有的操作都调用子类。这样,在需要对系统进行功能扩展时,只需要依据抽象类实现新的子类即可。如图所示,在扩展子类时,不仅可以拥有抽象类的共有属性和共有函数,还可以拥有自定义的属性和函数。

clip_image004

        2)多使用接口

与抽象类不同,接口只定义子类应该实现的接口函数,而不实现公有的功能。在现在大多数的软件开发中,都会为实现类定义接口,这样在扩展子类时实现该接口。如果要改换原有的实现,只需要改换一个实现类即可。如图所示,各子类由接口类定义了接口函数,只需要在不同的子类中编写不同的实现即可,当然也可以实现自有的函数。

clip_image005

      #13楼的回答是很中肯的,他强调了所有事情都是有范围的,就是要有个度,没有最好的,只有最合适的。就想开闭原则和其他原则、还有所有的设计模式的使用都是有范围的,所有说编程不仅是一门技术也是一门艺术;我们设计人员不是神,不能以不变应万变,但是我们要通过学习设计模式原则和设计模式做到以变应万变。

项目中来分析开闭原则

       打开EA,画一个简略三层架构的图,我们从这个rose图中来分析开闭原则。

clip_image006

       生成源文件:

clip_image007

   1: '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
   2: ''
   3: ''  Factory.vb
   4: ''  Implementation of the Class Factory
   5: ''  Generated by Enterprise Architect
   6: ''  Created on:      14-五月-2011 14:58:35
   7: ''  Original author: cjq
   8: ''  
   9: '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  10: ''  Modification history:
  11: ''  
  12: ''
  13: '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  14:  
  15:  
  16:  
  17: Option Explicit On
  18: Option Strict On
  19:  
  20: Imports Model.b.Package1
  21:  
  22: Namespace b.Package1
  23:     Public Class Factory
  24:  
  25:  

26: Private ReadOnly strAssemblyName As String = System.Configuration _

.ConfigurationSettings.AppSettings("DAL")

  27:  

28: Private ReadOnly strDB As String = System.Configuration _

.ConfigurationSettings.AppSettings("sql")

  29:  
  30:  
  31:         ''' 
  32:         ''' 实例化用户表类
  33:         ''' 
  34:         ''' 用户表类
  35:         ''' 2011-3-23 9:57 by cjq
  36:         Public Function CreateUserInfo() As IUserInfo
  37:             Dim className As String = strAssemblyName + "." + strDB + "UserInfo"

38: Return CType(Assembly.Load(strAssemblyName).CreateInstance _

(className), IUserInfo)

  39:         End Function
  40:  
  41:         ''' 
  42:         ''' 实例化学生信息类
  43:         ''' 
  44:         ''' 学生信息类
  45:         ''' 2011-3-23 11:18 by cjq
  46:         Public Function CreateStudentInfo() As IStuInfo
  47:             Dim className As String = strAssemblyName + "." + strDB + "StuInfo"

48: Return CType(Assembly.Load(strAssemblyName).CreateInstance _

(className), IStuInfo)

  49:         End Function
  50:  
  51:  
  52:     End Class ' Factory
  53:  
  54: End Namespace ' Package1

       将生成的代码完善之后(上面的代码是Factory类的代码),我们就能发现工厂类是完成实例化的,而sqlserverUserInfo和AccessUserInfo是两个不同数据库的DAL层类,这样我们如果变数据库的时候,我们就只需要添加相应的数据库DAL层类即可,这就是扩展,而且根本就不用修改。

 

       通过这个例子的说明相信大家对开闭原则有了一定的认识。当然读者如果认为这篇文章有哪里写的不好,或有什么不对的地方,望读者指正。