會說不在 SOLID 裡,是因為在維基找不到,但書上有寫,所以就拿出來騙天數好了。
原文:
Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
直譯:
每個單元應該對其他單元只能有有限的知識:只了解跟目前單元比較親近的單元。
程式寫了就是要拿來執行,從未執行過的程式碼比 bug 還要不如,因為連它是不是 bug 都不曉得。換言之,單元與單元之間是會有耦合的。這個原則在告訴我們該如何控制耦合的程度。
舉個例子:
有一位主管(Manager)很會寫程式,他的實作如下:
<?php
class Manager { public function work(Code $code) { $code->content .= ' + Manager code'; $this->build($code->content); }
public function build($content) { echo "$content 程式建置完畢\n"; }
}
class Code { public $content; public function __construct($content) { $this->content = $content; } }
$code = new Code('Legacy code');
$manager = new Manager(); $manager->work($code);
|
執行結果如下:
Legacy code + Manager code 程式建置完畢
|
問題
程式碼看似很正常,但問題總是發生在變化的時候:假如來了新的工程師,工程師該怎麼做事?看樣子好像也只能跟著主管傳承下來的做法來做:
<?php
class Engineer { public function work(Code $code) { $code->content .= ' + Engineer code'; $this->build($code->content); }
public function build($content) { echo "$content 程式建置完畢\n"; } }
$code = new Code('Legacy code');
$manager = new Manager(); $manager->work($code);
$engineer = new Engineer(); $engineer->work($code);
|
執行結果如下:
Legacy code + Manager code 程式建置完畢 Legacy code + Manager code + Engineer code 程式建置完畢
|
雖然看似能解決問題,但這樣其實已經違反單一職責原則了,因為 Code
只要內容物有變化,比方說 content
改成 source
,這樣會同時影響到 Manager
與 Engineer
的實作。
為什麼會這樣呢?因為主管和工程師對於程式碼的可控權限都太高了,造成程式碼的行為變化會同時影響大家操作方法。相信大家也有這樣的經驗,改流程、改框架、改部署、改測試、改寫法等等,都會對其他人造成不小的困擾。
重構的方法也很簡單,主管要適當授權團隊制定一下基本操作規範(interface)就好了,同時也把公開的東西盡可能減少。
<?php
interface Source { public function write($content); public function build(); }
class Code implements Source { private $content; public function __construct($content) { $this->content = $content; }
public function write($content) { $this->content .= " + $content"; }
public function build() { echo "$this->content 程式建置完畢\n"; } }
class Manager { public function work(Code $code) { $code->write('Manager code'); $code->build(); } }
class Engineer { public function work(Code $code) { $code->write('Manager code'); $code->build(); } }
$code = new Code('Legacy code');
$manager = new Manager(); $manager->work($code);
$engineer = new Engineer(); $engineer->work($code);
|
執行結果不變:
Legacy code + Manager code 程式建置完畢 Legacy code + Manager code + Engineer code 程式建置完畢
|
但重構後,我們會發現對 content
的細部處理改在 Code
裡面解決,其他人則使用 Code
提供的方法來達成任務。這樣的結果是讓 Code
的內聚性提高,程式碼就會越穩定。
今天不管是誰,只要會寫 code,會使用 Code
提供的 build()
方法,就能參與開發。
這就有點像把 Makefile 使用在團隊規範一樣。
<?php
class Newbie { public function work(Code $code) { $code->write('Newbie code'); $code->build(); } }
|
優點
程式不可能沒有耦合,但耦合過高又會讓破壞程式碼的內聚性,最小知識原則告訴我們,要把耦合的程度適度的縮小才是最好的。
參考資料