摘要:此模式的主要特點是,與不同,其數(shù)據(jù)模式遵循單一職責原則。圖代碼你可以在上找到這些代碼代理模式目的為昂貴或者無法復制的資源提供接口。圖代碼你可以在上找到這些代碼相關(guān)文章設(shè)計模式范例創(chuàng)建型設(shè)計模式
【搬運于GitHub開源項目DesignPatternsPHP】
項目地址:戳我2、結(jié)構(gòu)型設(shè)計模式
在軟件工程中,結(jié)構(gòu)型設(shè)計模式集是用來抽象真實程序中的對象實體之間的關(guān)系,并使這種關(guān)系可被描述,概括和具體化。
2.1 適配器模式 2.1.1 目的將某個類的接口轉(zhuǎn)換成與另一個接口兼容。適配器通過將原始接口進行轉(zhuǎn)換,給用戶提供一個兼容接口,使得原來因為接口不同而無法一起使用的類可以得到兼容。
2.1.2 例子數(shù)據(jù)庫客戶端庫適配器
使用不同的webservices,通過適配器來標準化輸出數(shù)據(jù),從而保證不同webservice輸出的數(shù)據(jù)是一致的
2.1.3 UML圖 2.1.4 代碼你可以在 GitHub 上找到這些代碼
BookInterface.php
Book.php
page = 1; } public function turnPage() { $this->page++; } public function getPage(): int { return $this->page; } }EBookAdapter.php
eBook = $eBook; } /** * This class makes the proper translation from one interface to another. */ public function open() { $this->eBook->unlock(); } public function turnPage() { $this->eBook->pressNext(); } /** * notice the adapted behavior here: EBookInterface::getPage() will return two integers, but BookInterface * supports only a current page getter, so we adapt the behavior here * * @return int */ public function getPage(): int { return $this->eBook->getPage()[0]; } }EBookInterface.php
Kindle.php
page++; } public function unlock() { } /** * returns current page and total number of pages, like [10, 100] is page 10 of 100 * * @return int[] */ public function getPage(): array { return [$this->page, $this->totalPages]; } }2.2 橋接模式 2.2.1 目的解耦一個對象的實現(xiàn)與抽象,這樣兩者可以獨立地變化。
2.2.2 例子Symfony DoctrineBridge
2.2.3 UML圖 2.2.4 代碼你可以在 GitHub 上找到這些代碼
Formatter.php
PlainTextFormatter.php
HtmlFormatter.php
%s", $text); } }Service.php
implementation = $printer; } /** * @param Formatter $printer */ public function setImplementation(Formatter $printer) { $this->implementation = $printer; } abstract public function get(): string; }HelloWorldService.php
implementation->format("Hello World"); } }PingService.php
implementation->format("pong"); } }2.3 組合模式 2.3.1 目的以單個對象的方式來對待一組對象
2.3.2 例子form類的實例包含多個子元素,而它也像單個子元素那樣響應(yīng)render()請求,當調(diào)用render()方法時,它會歷遍所有的子元素,調(diào)用render()方法
Zend_Config: 配置選項樹, 其每一個分支都是Zend_Config對象
2.3.3 UML圖 2.3.4 代碼你可以在 GitHub 上找到這些代碼
RenderableInterface.php
Form.php
"; foreach ($this->elements as $element) { $formCode .= $element->render(); } $formCode .= ""; return $formCode; } /** * @param RenderableInterface $element */ public function addElement(RenderableInterface $element) { $this->elements[] = $element; } }InputElement.php
"; } }TextElement.php
text = $text; } public function render(): string { return $this->text; } }2.4 數(shù)據(jù)映射器 2.4.1 目的數(shù)據(jù)映射器是一個數(shù)據(jù)訪問層,用于將數(shù)據(jù)在持久性數(shù)據(jù)存儲(通常是一個關(guān)系數(shù)據(jù)庫)和內(nèi)存中的數(shù)據(jù)表示(領(lǐng)域?qū)樱┲g進行相互轉(zhuǎn)換。其目的是為了將數(shù)據(jù)的內(nèi)存表示、持久存儲、數(shù)據(jù)訪問進行分離。該層由一個或者多個映射器組成(或者數(shù)據(jù)訪問對象),并且進行數(shù)據(jù)的轉(zhuǎn)換。映射器的實現(xiàn)在范圍上有所不同。通用映射器將處理許多不同領(lǐng)域的實體類型,而專用映射器將處理一個或幾個。
此模式的主要特點是,與Active Record不同,其數(shù)據(jù)模式遵循單一職責原則(Single Responsibility Principle)。
2.4.2 例子DB對象關(guān)系映射器(ORM): Doctrine2使用“EntityRepository”作為DAO
2.4.3 UML圖 2.4.4 代碼你可以在 GitHub 上找到這些代碼
User.php
username = $username; $this->email = $email; } /** * @return string */ public function getUsername() { return $this->username; } /** * @return string */ public function getEmail() { return $this->email; } }UserMapper.php
adapter = $storage; } /** * finds a user from storage based on ID and returns a User object located * in memory. Normally this kind of logic will be implemented using the Repository pattern. * However the important part is in mapRowToUser() below, that will create a business object from the * data fetched from storage * * @param int $id * * @return User */ public function findById(int $id): User { $result = $this->adapter->find($id); if ($result === null) { throw new InvalidArgumentException("User #$id not found"); } return $this->mapRowToUser($result); } private function mapRowToUser(array $row): User { return User::fromState($row); } }StorageAdapter.php
data = $data; } /** * @param int $id * * @return array|null */ public function find(int $id) { if (isset($this->data[$id])) { return $this->data[$id]; } return null; } }2.5 裝飾器 2.5.1 目的動態(tài)地為類的實例添加功能
2.5.2 例子Zend Framework: Zend_Form_Element 實例的裝飾器
Web Service層:REST服務(wù)的JSON與XML裝飾器(當然,在此只能使用其中的一種)
2.5.3 UML圖 2.5.4 代碼你可以在 GitHub 上找到這些代碼
Booking.php
BookingDecorator.php
booking = $booking; } }DoubleRoomBooking.php
ExtraBed.php
booking->calculatePrice() + self::PRICE; } public function getDescription(): string { return $this->booking->getDescription() . " with extra bed"; } }WiFi.php
booking->calculatePrice() + self::PRICE; } public function getDescription(): string { return $this->booking->getDescription() . " with wifi"; } }2.6 依賴注入 2.6.1 目的實現(xiàn)了松耦合的軟件架構(gòu),可得到更好的測試,管理和擴展的代碼
2.6.2 用例注入DatabaseConfiguration, DatabaseConnection將從$config獲得所需的所有內(nèi)容。沒有DI(依賴注入),配置將直接在DatabaseConnection中創(chuàng)建,這不利于測試和擴展它。
2.6.3 例子Doctrine2 ORM 使用了依賴注入,它通過配置注入了 Connection 對象。為了達到方便測試的目的,可以很容易的通過配置創(chuàng)建一個mock的 Connection 對象。
Symfony 和 Zend Framework 2 也有了專門的依賴注入容器,用來通過配置數(shù)據(jù)創(chuàng)建需要的對象(比如在控制器中使用依賴注入容器獲取所需的對象)
2.6.4 UML圖 2.6.5 代碼你可以在 GitHub 上找到這些代碼
DatabaseConfiguration.php
host = $host; $this->port = $port; $this->username = $username; $this->password = $password; } public function getHost(): string { return $this->host; } public function getPort(): int { return $this->port; } public function getUsername(): string { return $this->username; } public function getPassword(): string { return $this->password; } }DatabaseConnection.php
configuration = $config; } public function getDsn(): string { // this is just for the sake of demonstration, not a real DSN // notice that only the injected config is used here, so there is // a real separation of concerns here return sprintf( "%s:%s@%s:%d", $this->configuration->getUsername(), $this->configuration->getPassword(), $this->configuration->getHost(), $this->configuration->getPort() ); } }2.7 外觀模式 2.7.1 目的Facade模式的主要目標不是避免您必須閱讀復雜API的手冊。這只是副作用。主要目的是減少耦合并遵循Demeter定律。
Facade通過嵌入多個(當然,有時只有一個)接口來解耦訪客與子系統(tǒng),當然也降低復雜度。
Facade不會禁止你訪問子系統(tǒng)
你可以為一個子系統(tǒng)提供多個 Facade
因此一個好的 Facade 里面不會有 new 。如果每個方法里都要構(gòu)造多個對象,那么它就不是 Facade,而是生成器或者 [ 抽象 | 靜態(tài) | 簡單 ] 工廠方法。優(yōu)秀的 Facade 不會有 new,并且構(gòu)造函數(shù)參數(shù)是接口類型的。如果你需要創(chuàng)建一個新實例,則在參數(shù)中傳入一個工廠對象。
2.7.2 UML圖 2.7.3 代碼你可以在 GitHub 上找到這些代碼
Facade.php
bios = $bios; $this->os = $os; } public function turnOn() { $this->bios->execute(); $this->bios->waitForKeyPress(); $this->bios->launch($this->os); } public function turnOff() { $this->os->halt(); $this->bios->powerDown(); } }OsInterface.php
BiosInterface.php
2.8 連貫接口 2.8.1 目的用來編寫易于閱讀的代碼,就像自然語言一樣(如英語)
2.8.2 例子Doctrine2 的 QueryBuilder,就像下面例子中類似
PHPUnit 使用連貫接口來創(chuàng)建 mock 對象
Yii 框架:CDbCommand 與 CActiveRecord 也使用此模式
2.8.3 UML圖 2.8.4 代碼你可以在 GitHub 上找到這些代碼
Sql.php
fields = $fields; return $this; } public function from(string $table, string $alias): Sql { $this->from[] = $table." AS ".$alias; return $this; } public function where(string $condition): Sql { $this->where[] = $condition; return $this; } public function __toString(): string { return sprintf( "SELECT %s FROM %s WHERE %s", join(", ", $this->fields), join(", ", $this->from), join(" AND ", $this->where) ); } }2.9 享元 2.9.1 目的為了盡可能減少內(nèi)存使用,Flyweight與類似的對象共享盡可能多的內(nèi)存。當使用大量狀態(tài)相差不大的對象時,就需要它。通常的做法是保持外部數(shù)據(jù)結(jié)構(gòu)中的狀態(tài),并在需要時將其傳遞給flyweight對象。
2.9.2 UML圖 2.9.3 代碼你可以在 GitHub 上找到這些代碼
FlyweightInterface.php
CharacterFlyweight.php
name = $name; } public function render(string $font): string { // Clients supply the context-dependent information that the flyweight needs to draw itself // For flyweights representing characters, extrinsic state usually contains e.g. the font. return sprintf("Character %s with font %s", $this->name, $font); } }FlyweightFactory.php
pool[$name])) { $this->pool[$name] = new CharacterFlyweight($name); } return $this->pool[$name]; } public function count(): int { return count($this->pool); } }2.10 代理模式 2.10.1 目的為昂貴或者無法復制的資源提供接口。
2.10.2 例子Doctrine2 使用代理來實現(xiàn)框架特性(如延遲初始化),同時用戶還是使用自己的實體類并且不會使用或者接觸到代理
2.10.3 UML圖 2.10.4 代碼你可以在 GitHub 上找到這些代碼
BankAccount.php
HeavyBankAccount.php
transactions[] = $amount; } public function getBalance(): int { // this is the heavy part, imagine all the transactions even from // years and decades ago must be fetched from a database or web service // and the balance must be calculated from it return array_sum($this->transactions); } }BankAccountProxy.php
balance === null) { $this->balance = parent::getBalance(); } return $this->balance; } }2.11 注冊模式 2.11.1 目的要為整個應(yīng)用程序中經(jīng)常使用的對象實現(xiàn)中央存儲,通常只使用靜態(tài)方法(或使用單例模式)的抽象類來實現(xiàn)。請記住,這將引入全局狀態(tài),這在任何時候都應(yīng)該避免!而是使用依賴注入來實現(xiàn)它!
2.11.2 例子Zend Framework 1: Zend_Registry 持有應(yīng)用的logger對象,前端控制器等。
Yii 框架: CWebApplication 持有所有的應(yīng)用組件,如 CWebUser, CUrlManager, 等。
2.11.3 UML圖 2.11.4 代碼你可以在 GitHub 上找到這些代碼
Registry.php
相關(guān)文章:
PHP設(shè)計模式范例 — DesignPatternsPHP(1)創(chuàng)建型設(shè)計模式
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/29982.html
摘要:抽象工廠目的創(chuàng)建一系列相關(guān)或依賴的對象,而不指定它們的具體類。這個模式是一個真正的設(shè)計模式,因為它遵循了依賴反轉(zhuǎn)原則眾所周知這個代表了真正的面向?qū)ο蟪绦蛟O(shè)計。 【搬運于GitHub開源項目DesignPatternsPHP】 項目地址:戳我 1、創(chuàng)建型設(shè)計模式 在軟件工程中,創(chuàng)建型設(shè)計模式承擔著對象創(chuàng)建的職責,嘗試創(chuàng)建適合程序上下文的對象,對象創(chuàng)建設(shè)計模式的產(chǎn)生是由于軟件工程設(shè)計的問...
摘要:圖示代碼示例服務(wù)實例索引服務(wù)定義索引是否全局服務(wù)共享單例模式實例化省略服務(wù)實例化實現(xiàn)無法定位服務(wù)服務(wù)添加失敗感謝文中圖片來源來源網(wǎng)絡(luò) 什么是服務(wù)定位器 服務(wù)定位器(service locator)他知道如何定位(創(chuàng)建或者獲取)一個應(yīng)用所需要的服務(wù),服務(wù)使用者在實際使用中無需關(guān)心服務(wù)的實際實現(xiàn)。 有什么作用 實現(xiàn)服務(wù)使用者和服務(wù)的解耦,無需改變代碼而只是通過簡單配置更服服務(wù)實現(xiàn)。 UML...
摘要:面向?qū)ο笤O(shè)計模式通常以類別或?qū)ο髞砻枋銎渲械年P(guān)系和相互作用,但不涉及用來完成應(yīng)用程序的特定類別或?qū)ο蟆@锸洗鷵Q原則里氏代換原則是面向?qū)ο笤O(shè)計的基本原則之一。 通俗易懂的設(shè)計模式 零、使用 1、安裝 2、測試 一、什么是設(shè)計模式 二、設(shè)計模式的類型 三、設(shè)計模式的六大原則 四、UML類圖 1、看懂UML類圖 2、解釋 五、資料 前言:花了一些時間再次熟悉了一遍...
摘要:帶有兩個特殊的變量,專門用來達到這個目的一個是變量,它通過命令行把傳遞給腳本的參數(shù)保存為單獨的數(shù)組元素另一個是變量,它用來保存數(shù)組里元素的個數(shù)。 本文為轉(zhuǎn)載,原文鏈接: 參考文章 所有的PHP發(fā)行版,不論是編譯自源代碼的版本還是預創(chuàng)建的版本,都在默認情況下帶有一個PHP可執(zhí)行文件。這個可執(zhí)行文件可以被用來運行命令行的PHP程序。要在你的系統(tǒng)上找到這個可執(zhí)行文件,就要遵照下面的步驟: 1...
前言 在若干次前的一場面試,面試官看我做過python爬蟲/后端 的工作,順帶問了我些后端相關(guān)的問題:你覺得什么是后端? 送命題。當時腦瓦特了,答曰:邏輯處理和數(shù)據(jù)增刪改查。。。 showImg(https://user-gold-cdn.xitu.io/2019/4/24/16a4ed4fc8c18078); 當場被懟得體無完膚,羞愧難當。事后再反思這問題,結(jié)合資料總結(jié)了一下。發(fā)現(xiàn)自己學過的Re...
閱讀 2089·2021-09-29 09:35
閱讀 693·2021-09-08 09:36
閱讀 3402·2021-09-03 10:30
閱讀 2119·2019-08-30 14:21
閱讀 2915·2019-08-30 11:18
閱讀 3320·2019-08-29 17:31
閱讀 3148·2019-08-29 17:29
閱讀 1316·2019-08-29 17:13