面向对象设计原则之单一职责原则(SRP)

Web程序猿博客:http://blog.csdn.net/thinkercode

  这条原则曾经在 Tom DeMaro 和 Meilir Page-Jones 的著作中描述过,并称之为内聚性(cohesion)。他们把内聚性定义为:一个模块的组成元素之间的功能相关性。

单一职责原则(SRP)

单一职责原则(Single Responsibility Principle, SRP):就一个类而言,应该仅有一个引起它变化的原因。

  单一职责的原则告诉我们:在软件系统中,如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化肯呢过会消弱和抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏[ASD],事实上我们在做编程的时候很自然地就会跟一个类加各式各样的功能。
  单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则。我们会自然地把职责结合在一起,软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。

什么是职责

在SRP中,我们把职责定义为“变化的原因”(a reason for cheange)。如果你能够想到多于一个动机去改变一个类,那么这个类就具有多于一个的职责,有时我们很难注意到这一点。我们习惯于以组的形式去考虑职责。

  查看如下类库,这是一个网上的图片处理类,用来裁剪图片和生成缩略图的工具类,该类承担的职责非常多,用来打开不同类型的图片(jpeg,png,gif…),针对不同的裁剪和压缩方式进行计算,对图片进行压缩和裁剪,保存图片为不同类型。该类承担很多职责,如果现在这个类时针对GD库的裁图工具,那么将来由于种种原因采用GraphicsMagick处理图片,整个类都要改变,我相信很多人直接更换到更一个类进行处理了。
面向对象设计原则之单一职责原则(SRP)_第1张图片
例图1
  针对这个例子,我们对Images类的职责进行分离,保留Images对外的服务,把图片处理进行分离,新增一个ImagesHandle的图片处理接口,现阶段系统支持jpg和png图片的处理,因此JpegHandle和PngHandle实现ImagesHandle接口。Images中打开方法会根据图片类型调用不同的ImagesHandle实例,crop和thumb方法根据不同的处理方式进行计算,之后调用ImagesHandle实例的crop对图片进行裁剪,save方法会根据ImagesHandle的不同实例进行保存。具体类图如下:
面向对象设计原则之单一职责原则(SRP)_第2张图片
例图2
  改善的例子中Images作为统一的服务接口,也许很多人都觉得这个类图已经没有问题,但是Images同时负责裁图运算,又负责协调ImagesHandle实例,那么这个职责分离还不是很完善。这只是一个例子,还没有得以实现,在实现中还会发现各个ImagesHandle之间的类型转换没能实现等问题,其实改善这些问题也很简单,把裁图算法单独用一个类实现,把ImagesHandle的save()改成save(ImagesHandle handle,  file=null)就可以实现类型转换了。
  

为什么要遵守SRP?

  1. 可以减少类之间的耦合
      如果减少类之间的耦合,当需求变化时,只修改一个类,从而也就隔离了变化;如果一个类有多个不同职责,它们耦合在一起,当一个职责发生变化时,可能会影响其他职责。
  2. 提高类的复用性
      修理电脑比修理电视机简单多了。主要原因就在于电视机各个部件之间的耦合性太高,而电脑则不同,电脑的内存、硬盘、声卡、网卡、键盘灯部件都可以很容易地单独拆卸和组装。某个部件坏了,换上新的即可。
  3. 提高可读性
  4. 提高可读性
  5. 降低类的复杂性,实现什么样的职责都有清晰的定义
  6. 降低变更引起的风险,对系统扩展性和维护性很有帮助

      使用单一职责原则有一个问题,“职责”没有一个明确的划分标准,如果把职责划分的太细会导致接口和实现类的剧增,反而提高了复杂度,降低了代码的可维护性。所以使用这个职责的时候还要具体情况具体分析。建议就是接口一定要采用单一职责原则,实现类设计上尽可能做到单一职责原则,最好是一个原因引起一个类的变化。
      单一职责原则不仅体现在类设计上,对于类的方法、函数、类库包、模块、组件等都应该遵循单一职责原则,只有一个变化能引起封装的代码变化。

你可能感兴趣的:(设计模式)