Single Responsibility Principle defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to change.
SRP是Bob大叔提出的一个重要设计原则。SRP强调每一个类或模块只有一个变化的原因。但这个唯一的变化原因不太容易理解,不少人以为单一职责就是指的每个类都尽量设计成只有一个方法,只做一件事。真正理解SRP关键在于理解职责的层次性。关于SRP原则一个很好的例子是汽车:汽车作为一个整体是单一职责的,它的职责就是满足驾驶需要;而汽车又是由发动机、底盘、轮胎等等部件构成的,每一个部件的职责也是单一的,发动机的职责就是提供动力,轮胎的职责就是转动;进一步发动机还可以细分为更低层次的零件,每个零件其实也是单一职责的。所以,职责是有层次的,任何系统或对象都负责所属层次的职责。系统的职责是作为一个单一且完备的整体存在的,而不是子系统层次职责的简单累加。这就是职责层次性原理。
职责的层次性是它的一种性质,但并不说明职责的本质。那么职责的本质是什么呢?我认为,职责是对需求的满足。职责层次性来源于需求层次性。需求是有层次的,用户也是有层次的。汽车需求=>发动机需求=>螺丝需求=>钢材需求就是需求的层次性;车的用户=>汽车制造商=>发动机生产商=>螺丝生产商=>…就是用户的层次性。所以,SRP中提到的“变化原因”即是需求变化,“唯一的变化原因”暗示了需求的层次性,如果需求层次与职责层次相对应,那么每一个系统在所处的层次上的确只会有一个变化的原因。
职责层次性的背后是需求层次性,那么需求层次性又是哪里来的呢?需求层次性来源于设计!对于汽车的用户来讲,他的需求是汽车整体这个层次的,至于汽车部件的设计则不属于他所关心的范畴。而发动机、轮胎等需求来源于汽车设计者对汽车结构的设计,这就是说为满足高层系统需求所进行的设计产生了子系统的需求,而子系统的需求又进一步产生了子子系统的设计,这就是设计层次性。需求=>设计=>需求=>设计…,需求和设计就像鸡生蛋,蛋生鸡一样层层地细化,我们称这种设计方式为职责驱动设计。
需要指出的是职责驱动设计所产生的层次性仅仅是若干系统层次性的一种。对系统划分层次的方法有很多很多种,传统的3层架构也是一种层次性,那么职责驱动设计产生的层次性有什么不同呢?我们举一个例子来说明,比如:一家公司可以先按项目组来划分,项目组再划分成开发和测试;同样,一家公司也可以先划分成开发部门和测试部门,再各部门抽调员工来组成项目组。系统层次划分方法的多样性本质上是由于系统的多元性决定的,一个人从项目看属于A项目,按工种来看属于测试,按学历来看属于研究生,按性别来看属于男性等等。而职责驱动设计的特点是把功能作为第一级的分层标准,每一层都是一种功能内聚!即各子系统是为实现高层职责而进行功能协作聚合到一起的,或者说各子系统是一种功能耦合关系。前面例子中,先按项目组划分的方式是一种功能内聚方式,而先按开发和测试部门划分则不是。良好的系统设计应具有高内聚、低耦合的特点,功能耦合被认为是一种最佳的耦合方式。比如:Socket类具有Connect、Disconnect、Send、Receive等功能,它们是作为完整地实现Socket通信功能而耦合在一起的,是一种值得提倡的高内聚方式。
职责层次性又决定了测试层次性。一辆汽车的测试需要从螺丝测试到轮胎测试到整车测试,这才能让人放心每一个环节都不出问题。职责是有层次的,类是有层次的,关于类的单元测试也是有层次的。所以,单元测试并不像不少人所误解的那样只测“螺丝”级别。虽然单元测试可能达不到“整车”测试的级别,但起码达到“轮胎”测试的级别是可能的。除了单元测试本身的层次性,向外扩展,集成测试、验收测试形成了更大的测试反馈链,每一层测试都会形成对该层系统的反馈,这就是反馈层次性。
上面从单一职责原则入手,介绍了职责驱动设计所产生的各种层次性,包括:需求层次性,职责层次性,设计层次性,测试层次性,反馈层次性。这些不同的层次性具有内在的一致性,因为它们都源于系统层次性。每一种层次性是系统这个多维对象从不同维度所建立的视图,从需求的角度看是需求层次性,从测试角度看是测试层次性。所以,理解系统的多维度与多层次是分析理解问题的根本。
上面是我对系统和设计的一点粗浅的认识,文中错误和不足之处欢迎批评指正!