摘要:此模式的主要特点是,与不同,其数据模式遵循单一职责原则。图代码你可以在上找到这些代码代理模式目的为昂贵或者无法复制的资源提供接口。图代码你可以在上找到这些代码相关文章设计模式范例创建型设计模式
【搬运于GitHub开源项目DesignPatternsPHP】
项目地址:戳我2、结构型设计模式
在软件工程中,结构型设计模式集是用来抽象真实程序中的对象实体之间的关系,并使这种关系可被描述,概括和具体化。
2.1 适配器模式 2.1.1 目的将某个类的接口转换成与另一个接口兼容。适配器通过将原始接口进行转换,给用户提供一个兼容接口,使得原来因为接口不同而无法一起使用的类可以得到兼容。
2.1.2 例子数据库客户端库适配器
使用不同的webservices,通过适配器来标准化输出数据,从而保证不同webservice输出的数据是一致的
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 目的解耦一个对象的实现与抽象,这样两者可以独立地变化。
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类的实例包含多个子元素,而它也像单个子元素那样响应render()请求,当调用render()方法时,它会历遍所有的子元素,调用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 数据映射器 2.4.1 目的数据映射器是一个数据访问层,用于将数据在持久性数据存储(通常是一个关系数据库)和内存中的数据表示(领域层)之间进行相互转换。其目的是为了将数据的内存表示、持久存储、数据访问进行分离。该层由一个或者多个映射器组成(或者数据访问对象),并且进行数据的转换。映射器的实现在范围上有所不同。通用映射器将处理许多不同领域的实体类型,而专用映射器将处理一个或几个。
此模式的主要特点是,与Active Record不同,其数据模式遵循单一职责原则(Single Responsibility Principle)。
2.4.2 例子DB对象关系映射器(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 目的动态地为类的实例添加功能
2.5.2 例子Zend Framework: Zend_Form_Element 实例的装饰器
Web Service层:REST服务的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 目的实现了松耦合的软件架构,可得到更好的测试,管理和扩展的代码
2.6.2 用例注入DatabaseConfiguration, DatabaseConnection将从$config获得所需的所有内容。没有DI(依赖注入),配置将直接在DatabaseConnection中创建,这不利于测试和扩展它。
2.6.3 例子Doctrine2 ORM 使用了依赖注入,它通过配置注入了 Connection 对象。为了达到方便测试的目的,可以很容易的通过配置创建一个mock的 Connection 对象。
Symfony 和 Zend Framework 2 也有了专门的依赖注入容器,用来通过配置数据创建需要的对象(比如在控制器中使用依赖注入容器获取所需的对象)
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通过嵌入多个(当然,有时只有一个)接口来解耦访客与子系统,当然也降低复杂度。
Facade不会禁止你访问子系统
你可以为一个子系统提供多个 Facade
因此一个好的 Facade 里面不会有 new 。如果每个方法里都要构造多个对象,那么它就不是 Facade,而是生成器或者 [ 抽象 | 静态 | 简单 ] 工厂方法。优秀的 Facade 不会有 new,并且构造函数参数是接口类型的。如果你需要创建一个新实例,则在参数中传入一个工厂对象。
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 使用连贯接口来创建 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 目的为了尽可能减少内存使用,Flyweight与类似的对象共享尽可能多的内存。当使用大量状态相差不大的对象时,就需要它。通常的做法是保持外部数据结构中的状态,并在需要时将其传递给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 使用代理来实现框架特性(如延迟初始化),同时用户还是使用自己的实体类并且不会使用或者接触到代理
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 目的要为整个应用程序中经常使用的对象实现中央存储,通常只使用静态方法(或使用单例模式)的抽象类来实现。请记住,这将引入全局状态,这在任何时候都应该避免!而是使用依赖注入来实现它!
2.11.2 例子Zend Framework 1: Zend_Registry 持有应用的logger对象,前端控制器等。
Yii 框架: CWebApplication 持有所有的应用组件,如 CWebUser, CUrlManager, 等。
2.11.3 UML图 2.11.4 代码你可以在 GitHub 上找到这些代码
Registry.php
相关文章:
PHP设计模式范例 — DesignPatternsPHP(1)创建型设计模式
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/29982.html
摘要:抽象工厂目的创建一系列相关或依赖的对象,而不指定它们的具体类。这个模式是一个真正的设计模式,因为它遵循了依赖反转原则众所周知这个代表了真正的面向对象程序设计。 【搬运于GitHub开源项目DesignPatternsPHP】 项目地址:戳我 1、创建型设计模式 在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问...
摘要:图示代码示例服务实例索引服务定义索引是否全局服务共享单例模式实例化省略服务实例化实现无法定位服务服务添加失败感谢文中图片来源来源网络 什么是服务定位器 服务定位器(service locator)他知道如何定位(创建或者获取)一个应用所需要的服务,服务使用者在实际使用中无需关心服务的实际实现。 有什么作用 实现服务使用者和服务的解耦,无需改变代码而只是通过简单配置更服服务实现。 UML...
摘要:带有两个特殊的变量,专门用来达到这个目的一个是变量,它通过命令行把传递给脚本的参数保存为单独的数组元素另一个是变量,它用来保存数组里元素的个数。 本文为转载,原文链接: 参考文章 所有的PHP发行版,不论是编译自源代码的版本还是预创建的版本,都在默认情况下带有一个PHP可执行文件。这个可执行文件可以被用来运行命令行的PHP程序。要在你的系统上找到这个可执行文件,就要遵照下面的步骤: 1...
前言 在若干次前的一场面试,面试官看我做过python爬虫/后端 的工作,顺带问了我些后端相关的问题:你觉得什么是后端? 送命题。当时脑瓦特了,答曰:逻辑处理和数据增删改查。。。 showImg(https://user-gold-cdn.xitu.io/2019/4/24/16a4ed4fc8c18078); 当场被怼得体无完肤,羞愧难当。事后再反思这问题,结合资料总结了一下。发现自己学过的Re...
阅读 2078·2021-09-29 09:35
阅读 673·2021-09-08 09:36
阅读 3388·2021-09-03 10:30
阅读 2108·2019-08-30 14:21
阅读 2904·2019-08-30 11:18
阅读 3305·2019-08-29 17:31
阅读 3135·2019-08-29 17:29
阅读 1299·2019-08-29 17:13