Re: [概念] single responsibility principle

楼主: tinlans ( )   2010-01-21 15:33:50
※ 引述《hsnucsc (hsnugo)》之铭言:
: 我找了很多网站
: 都将解释SRP成: 每一个物件, 应该要只有单一的responsibility
: 而将responsibility解释成: 只有一个理由去改变物件
: 但是我还是觉得responsibility这个词很模糊
: (如果直接翻译成中文, "责任", 仍然很难知道这个责任的大小)
这个责任是一个够大的责任。
因为你不是从标准路线走到这一步,
所以大概跟你说明一下好了。
传统 use-case driven 的开发,
会先从零散的问题里整理出比较明确的 problem statements,
接着从那里面区分出 functional/non-functional requirements 来。
use-case model 主要在模塑的是 functional requirements,
经过对前面得到的文字资料做名词和动词的分析后,
可以找到 actors 和 use cases。
在 use cases 被找到之后,
你的“需求分析工具”会要求你撰写 use case specifications,
格式大概是:
Use Case Specification: <这里填 use case 的名字>
1. Use Case Name
1.1 Brief Description
2. Flow of Events
2.1 Basic Flow
2.2 Alternative Flows
3. Special Requirements
...
在 2. 的部分要求你描述的,
就是整个 use case 从开始到结束要做的事情。
所谓的 basic flow 是很顺利的一直线走到底的流程,
没有所谓的特例状况和分支,
特例状况和分支都被描述在 alternative flows 上。
一般来说使用 UML 开发的话,
这部份也时常搭配 activity diagrams 来进行。
前言就讲到这里,
有一点长;
主要目的只有告诉你什么叫 flow of events,
还有它是怎么来的。
flow of events 是所谓“需求规格”的一部份。
对 flow of events 做 textual analysis,
你将会得到一群名词和动词,
一个有效的名词一般来说就会成为一个 class。
我想到这边你还是很熟悉,
但是这背后还有其它的意义。
你在描述 flow of events 时,
也同时在描述每个名词对某些行为的责任。
SRP 并不是无限上纲到脱离 requirements 让你停不下来,
你的一切 analysis 和 design 都必须基于 requirements 进行。
就像做学术研究,
一个论文题目总是不会解决所有问题,
而是会设定一些限制条件后再对有限的问题进行拆解;
实务面的软件设计更是如此。
责任的大小,
完全视你的需求而定,
不然你所有的东西恐怕都要定义到原子或夸克去了。
进行 SRP 分析或填写 CRC 卡的时候,
请记得看着 flow of events 做,
如果你没有这种东西,
就看看 flow charts 或 activity diagrams。
这些东西里都没有描述到的更细部责任,
那就不需要考虑,
你不需要把责任 delegate 给一个无效甚至不存在的名词。
在设计阶段,
SRP 常跟 OCP 搭配,
而 OCP 常跟 strategy pattern 搭配。
strategy pattern 负责将各种行为做分类,
因此改变行为常常是“新增” concrete strategy,
以及对 factory method (或 creation method) 的修改。
除非你需要新增的是 strategy 的 family (即 abstract strategy 或 interface),
才有可能需要去动到 context class。
因为这三种东西通常都有连动关系,
所以当你的“行为”本身根据需求并不会有“一个家族”的行为集时,
你是不需要再另外把责任再往外 delegate 给其它 classes。
以上两段应该大概可以告诉你“什么时候该停下来”了,
简单来说,
一切都环绕在需求规格上;
其实我也很想直接推一句“看需求决定”来回你就好了,
但是你可能会觉得很抽象,
然后将来可能又会有其他人跑来问一样的问题。
: 以书上的例子而言
: Automobile 车子有很多功能
: start()
: stop()
: changeTiles(Tile [*])
: drive()
: wash()
: checkOil()
: getOil()
: 应该要被分解成
: Automobile
: start()
: stop()
: getOil()
: Driver
: drive(Automobile)
: Carwash
: wash()
: Mechanic
: changeTires(Automobile, Tire[*])
: checkOil(Automible)
: 有一些method移交到其他物件处理
: 但是....
: 1. 假设Automible有
: body, front-left_tire, front_right_tire, back-left-tire, back_right_tire
: changeTires()为了要change车子的轮胎
: 势必要改变其四个轮胎
: 我猜写法是
: changeTires(Automobile au, Tire[*] tires)
: au.set_front_left_tire(tires[0]);
: au.set_front_right_tire(tires[1]);
: ....
: 这样为什么不直接把changeTires这件事直接委派给Automible去做
: 同样的道理, 如果其他drive, wash等method, 需要get or set
: 来知道Automible的细节, 那何不直接把这样工作交给Automible做
你把这世界简单化了。
一方面也是因为你看的书不是从头到尾 run 一个 project 给你看,
确实很容易让你因为对“需求”的资讯不足,
使得你对例子的理解与作者假设的情境不同。
一个物件被委派责任的原因,
主要是因为它“了解如何完成这个任务”,
也就是说包括这项任务的细节在内,
并不是你想的单纯 set/get 就好了,
Automible 本身可能提供非常多 method 让你 set/get 细部的参数
但是只有 Mechanic 知道要如何正确的 set 它们,
这中间可能还会有一些操作机械的流程,
可能还会有一些基本的安全检测等等;
当然这一些要看你的 flow of events 有没有描述到。
: 2. 这样好像又回到procedural programming
: data跟function是分开的, data当作function的input后, 由function来处理data
: 在这里, Automobile是要处理的data
: 而Driver, Carwash, Mechanic则有点像是处理data的function
: 再举个例子:
: 今天我们需要一个铁路线路网, 上面有多条线路, 多个车站
: 且在给予起点和终点后, 可以找出一个起点到终点的path, 并印出来
: 如果是我来设计的话
: class会有Subway, Line, Station, Route
: Subway.find(Sation s, Sation t)后, return 一个Route
: Route.print()印出path
: 但是书上的方法,
: class会有Subway, Connection, Station, Printer
: (Line, Connection的差异先不讨论)
: 他用Printer来印一个List route(有Connection跟Station)
: 于是, Printer在print的method里
: 必须要不停的用route.getXX(), station.getXX() ......
: 这感觉很像是Printer在处理一个Data
: 为什么不直接把print的工作给statoin, 给route呢
Printer 可以做相当简化的工作,
比方说它就是只提供 print(String),
也就是字串的打印;
station 和 route 并不需要知道如何打印一个字串。
Route.print() 可能要做比你想像中还要多的事情,
比方说把内部的资料表示法转换成有意义、易读易懂且可打印的字串,
才把打印“字串”的责任交给 Printer。
: java Exception 不是也有 printStackTrace, 并没有说特别把print的工作交给别人啊?
: 上面是增加新的物件来处理
: 我也有找到另一个方法, 是增加interface
: http://www.codingefficiency.com/2009/07/18/
: solid-s-single-responsibility-principle/
: http://0rz.tw/QP6hs (缩过的网址)
: 不过仍然让人很难分辨responsibility
: 说严格一点, 好像每个method, 都有理由改变
: 但是又不可能把每个method都新增一个物件去处理这项功能
: 希望有人可以帮忙解答
: 谢谢

Links booklink

Contact Us: admin [ a t ] ucptt.com