會說不在 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('Engineer 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();
}
}
程式不可能沒有耦合,但耦合過高又會讓破壞程式碼的內聚性,最小知識原則告訴我們,要把耦合的程度適度的縮小才是最好的。
找到錯字,class Engineer 裡的 Manager code
要改成 Engineer code
:
...
class Engineer
{
public function work(Code $code)
{
$code->write('Manager code'); // << 是 Engineer code
$code->build();
}
}
$code = new Code('Legacy code');
$manager = new Manager();
$manager->work($code);
$engineer = new Engineer();
$engineer->work($code);
神抓錯XD