第二章 面向?qū)ο蟮脑O(shè)計原則
在面向?qū)ο笾?,類是基本單位,各種設(shè)計都是圍繞著類來進行的。類與類之間的關(guān)系,構(gòu)成了設(shè)計模式的大部分內(nèi)容
2.1 面向?qū)ο笤O(shè)計的五大原則
1、單一職責原則(Single Pesponsibility Principle,SRP)
- 含義
1、避免相同的職責分散到不同的類中
2、避免一個類承擔太多的職責 - 作用
1、減少類之間的耦合
2、提高類的復(fù)用性
數(shù)據(jù)庫操作,SNS網(wǎng)站的動態(tài)實現(xiàn)
實例:餐館示例
/**
* 廚師類,命令接受者與執(zhí)行者
*/
class cook {
public function meal() {
echo "番茄炒蛋","<br/>";
}
public function drink() {
echo "紫菜蛋花湯","<br/>";
}
public function ok() {
echo "完畢","<br/>";
}
}
/**
* 命令接口(服務(wù)員)
*/
interface Waiter {
public function execute();
}
/**
* 模擬服務(wù)員與廚師的交互過程
*/
class MealWaiter implements Waiter {
private $cook;
public function __construct(cook $cook) {//類型限定,下同
$this->cook = $cook;
}
public function execute() {
$this->cook->meal();
}
}
class DrinkWaiter implements Waiter {
private $cook;
public function __construct(cook $cook) {
$this->cook = $cook;
}
public function execute() {
$this->cook->drink();
}
}
/**
* 顧客點菜
*/
class Custommers {
private $mealWaiter;
private $drinkWaiter;
public function addWaiter(Waiter $mealWaiter, Waiter $drinkWaiter) {//類型限定
$this->mealWaiter = $mealWaiter;
$this->drinkWaiter = $drinkWaiter;
}
public function callmeal() {
$this->mealWaiter->execute();
}
public function calldrink() {
$this->drinkWaiter->execute();
}
}
/**
* 實現(xiàn)命令模式
*/
$custommer = new Custommers;//一個顧客
$cook = new cook;//一個廚師
$mealWaiter = new MealWaiter($cook);//一個點菜的服務(wù)員
$drinkWaiter = new DrinkWaiter($cook);//一個點湯的服務(wù)員
$custommer->addWaiter($mealWaiter, $drinkWaiter);//叫來這兩個服務(wù)員
$custommer->callmeal();//點菜
$custommer->calldrink();//點湯
- 需要遵循的做法
1、根據(jù)業(yè)務(wù)流程,把業(yè)務(wù)對象提煉出來
標準化業(yè)務(wù)鏈后,對業(yè)務(wù)對象內(nèi)部進一步處理,把第一次標準化視為最高層抽象,第二次視為次高層抽象
2、職責的分類需要注意
規(guī)劃好各自的職責范圍
2、接口隔離原則(Interface Segregation Principle, ISP)
- 接口隔離
~ 一個類對另外一個類的依賴性應(yīng)當是建立在最小的接口上
~ 接口使用方程序不應(yīng)該依賴它不需要的接口方法 - 對接口的污染
~ 定制化服務(wù)設(shè)計,使用接口的多重繼承實現(xiàn)對不同的接口的組合,從而對外提供組合功能。
~ 高內(nèi)聚:接口應(yīng)該具備一些基本的功能,能獨一完成一個基本的任務(wù),而不能過于細化
~ 處理方法:* 利用委托分離接口 * 利用多繼承分離接口
3、開放-封閉原則 (Open-Close Principle, OCP)
- 基本思想
1、Open(Open for extension):模塊的行為必須是開放、支持擴展的,而不是僵化的。
2、Closed (Closed for modification):在對模塊的功能進行擴展時,不應(yīng)該影響已有的程序模塊 - 一個模塊在擴展性方面應(yīng)該是開放的而在更改性方面應(yīng)該是封閉的
- 示例
<?php
//開放封閉原則的示例:播放器
interface process {
public function process();
}
//編碼
class playerencode implements process {
public function process() {
echo "encode","<br/>";
}
}
//輸出
class playeroutput implements process {
public function process() {
echo "output","<br/>";
}
}
//播放器的線程調(diào)度管理器
class playprocess {
private $message = NULL;
public function __construct() {
}
public function callback(event $event) {
$this->message = $event->click();
if ($this->message instanceof process) {//instanceof:1、判斷一個對象是否是某個類的實例;2、判斷一個對象是否實現(xiàn)了某個接口
$this->message->process();
}
}
}
//播放器的事件處理類,對事件進行分揀
class event {
private $m;
public function __construct($me) {
$this->m = $me;
}
public function click() {
switch ($this->m) {
case 'encode':
return new playerencode();
break;
case 'output':
return new playeroutput();
break;
}
}
}
//播放器的事件處理邏輯
class mp4 {
public function work() {
$playProcess = new playProcess();
$playProcess->callback(new event('encode'));
$playProcess->callback(new event('output'));
}
}
//實現(xiàn)
$mp4 = new mp4();
$mp4->work();
- 如何遵守OCP原則
1、在設(shè)計方面充分應(yīng)用抽象和封裝思想
~ 找出各種可變因素,將之封裝
~ 一種可變因素封裝在一個對象中
2、在系統(tǒng)功能編程實現(xiàn)方面應(yīng)用面向接口的編程
~ 當需求發(fā)生變化時,可以提供該接口新的實現(xiàn)類,以求適應(yīng)變化
4、替換原則/里氏替換原則(Liskov Substitution Principle, LSP)
- 針對濫用繼承的問題提出的設(shè)計原則
- 子類必須能夠替換掉它們的父類,并出現(xiàn)在父類的任何地方
- 遵循方式
1、父類的方法都要在子類中實現(xiàn)或者重寫,并且派生類只實現(xiàn)其抽象類中聲明的方法,而不應(yīng)給出多余的方法定義或?qū)崿F(xiàn)
2、在客戶端程序中只應(yīng)該使用父類對象而不應(yīng)當直接使用子類對象,這樣可以實現(xiàn)運行期綁定(動態(tài)多態(tài))
5、依賴倒置原則(Dependence Inversion Principle, DIP)/IOC(Inversion of Control)
- 上層模塊不應(yīng)該依賴于下層模塊,它們共同依賴于同一個對象(父類不能依賴子類,它們都要依賴抽象類)
- 抽象不能依賴于具體,具體應(yīng)該依賴于抽象