淄博三合一网站开发,友情链接代码美化,广东智能网站建设哪家有,建设银行 网站设置密码什么是模式#xff1f;#xff1f; 有经验的00开发者(以及其他的软件开发者)建立了既有通用原则又有惯用方案的指令系统来指导他们编制软件。如果以结构化形式对这些问题、解决方案和命名进行描述使其系统化#xff0c;那么这些原则和习惯用法就可以称为模式。例如#xff…什么是模式 有经验的00开发者(以及其他的软件开发者)建立了既有通用原则又有惯用方案的指令系统来指导他们编制软件。如果以结构化形式对这些问题、解决方案和命名进行描述使其系统化那么这些原则和习惯用法就可以称为模式。例如下面是一个模式样例: 模式名称: 信息专家(Information Expert) 问题: 给对象分配职责的基本原则是什么? 解决方案: 给类分配一种职责使其具有完成该职责所需要的信息。 在OO设计中模式是对问题和解决方案的已命名描述它可以用于新的语境。理想情况下 模式为在变化环境中如何运用和权衡其解决方案给出建议。对于特定问题可以应用许多模式 为对象分配职责。 简单地讲好的模式是成对的问题/解决方案并且具有广为人知的名称它能用于新 的语境中同时对新情况下的应用、权衡、实现、变化等给出了建议。
模式具有名称一重要! 软件开发是一个年轻领域。年轻领域中的原则缺乏大家广泛认可的名称这为沟通和培训带来了困难。模式具有名称例如信息专家和抽象工厂。对模式、设计思想或原则命名具有以下好处: ·它支持将概念条理化地组织为我们的理解和记忆。 ·它便于沟通。 模式被命名并且广泛发布后(我们都同意使用这个名字)我们就可以在讨论复杂设计思想时使用简语(或简图)这可以发挥抽象的优势。看看下面两个软件开发者之间使用模式名称的讨论: Jill:“嗨!Jack对于这个持久性子系统让我截图时论一下外观(Fagade)的服务。我们将对Mappers使用抽象工厂对延迟具体化使用代理(Proxy)。” Jack:“你刚才究竟说了什么呀! Jill:“喂!看这儿……”
‘新模式”是一种矛盾修饰法 新模式如果描述的是新思想则应当被认为是一种矛盾修饰法。术语“模式”的真实含义是长期重复的事物。设计模式的要点并不是要表达新的设计思想。恰恰相反优秀模式的意图是将已有的经过验证的知识、惯用法和原则汇编起来;磨砺的越多、越悠久、使用得越广泛这样的模式就越优秀。 因此GRASP模式陈述的并不是新思想它们只是将为广泛使用的基本原则命名并其汇总 起来。对于OO设计专家而言GRASP模式(其思想而非名称)应作为其基础和熟练掌握的原则。 这是最关键的!
GOF关于设计模式的著作 Kent Beck(也因极限编程而闻名)在20世纪80年代中期首先提出了软件命名模式的思想。然而在模式、00设计和软件设计书籍的历史上1994年是一个重要的里程碑。极为畅销并产生巨大影响Design Patterns一书[GHJV95]就是在这一年出版的它的作者是Gamma、Helm、Johnson和Vlissides。这本书被认为是设计模式的“圣经”它描述了23个00设计模式并且命名为策略(Strategy)、适配器(Adaptor)等。因此这四个人提出的模式被称为GOF(或“四人帮”)设计模式。 然而Design Patterns一书不是入门类书籍读者要有一定的OO设计和编程知识而且书 中的大部分代码是用C编写的。
GRASP是一组模式或原则吗 GRASP定义了9个基本O0设计原则或基本设计构件。有些人会问“难道GRASP描述的是原则而不是模式吗?”《设计模式》一书的序言给出了答案: 某人的模式是其他人的原始构造块。 本书并不注重模式的标识和描述而更关注模式的实用价值即模式是一种优秀的学习工具可以用来命名、表示和记忆那些基本和经典的设计思想。 一些GRASP原则是对其他设计模式的归纳 上述适配器模式的使用可以视为某些GRASP构造模块的特化: 适配器支持防止变异因为它通过应用了接口和多态的间接对象改变了外部接口或第三方软件包。 问题是什么?模式过多! Pattern Almanac 2000[Rising00]列出了大约500种设计模式并且此后又发布了数百种模式。如此之多的模式使求知欲望强烈的程序员都没有时间去实际编程了。
解决方案:找到根本原则 是的对于有经验的设计者来说详细了解和记住50种以上最重要的设计模式非常重要但是很少有人能够学习或记住1000个模式因此需要对这些过量的模式进行有效分类。 但是现在有好消息了:大多数设计模式可以被视为少数几个GRASP基本原则的特化。这样除了能够有助于加速对详细设计模式的学习之外而且发现其根本的基本主题(防止变异、多态、间接性等)更为有效它能够帮助我们透过大量细节发现应用设计技术的本质。 示例:适配器和GRASP 图说明了我的观点可以用GRASP原则的基本列表来分析详细的设计模式。UML的泛化关系可以用来指出概念上的连接。目前这种思想可能过于理论化。但这是必要的当你花费了数年应用那些大量的设计模式后你会越来越体会到本质主题的重要性而极为细节化的适配器或策略等任何模式都将变得次要。 适配器与某些GRASP核心原则的关系 PHP的35种设计模式
模式
三个大类。
1. 创建型
在软件工程中创建型设计模式是处理对象创建机制的设计模式试图以适当的方式来创建对象。对象创建的基本形式可能会带来设计问题亦或增加了设计的复杂度。创建型设计模式通过控制这个对象的创建方式来解决此问题。
2. 结构型
在软件工程中结构型设计模式是通过识别实体之间关系来简化设计的设计模式。
3. 行为型
在软件工程中行为设计模式是识别对象之间的通用通信模式并实现这些模式的设计模式。 通过这样做这些模式增加了执行此通信的灵活性。 创建模式
1、抽象工厂模式Abstract Factory 目的
在不指定具体类的情况下创建一系列相关或依赖对象。 通常创建的类都实现相同的接口。 抽象工厂的客户并不关心这些对象是如何创建的它只是知道它们是如何一起运行的。
UML图 代码
Product.php
?phpnamespace DesignPatterns\Creational\AbstractFactory;
interface Product
{public function calculatePrice(): int;
}
ShippableProduct.php
?phpnamespace DesignPatterns\Creational\AbstractFactory;
class ShippableProduct implements Product
{/*** var float*/private $productPrice;/*** var float*/private $shippingCosts;public function __construct(int $productPrice, int $shippingCosts){$this-productPrice $productPrice;$this-shippingCosts $shippingCosts;}public function calculatePrice(): int{return $this-productPrice $this-shippingCosts;}
}
DigitalProduct.php
?phpnamespace DesignPatterns\Creational\AbstractFactory;
class DigitalProduct implements Product
{/*** var int*/private $price;public function __construct(int $price){$this-price $price;}public function calculatePrice(): int{return $this-price;}
}
ProductFactory.php
?phpnamespace DesignPatterns\Creational\AbstractFactory;
class ProductFactory
{const SHIPPING_COSTS 50;public function createShippableProduct(int $price): Product{return new ShippableProduct($price, self::SHIPPING_COSTS);}public function createDigitalProduct(int $price): Product{return new DigitalProduct($price);}
}
Test
Tests/AbstractFactoryTest.php
?phpnamespace DesignPatterns\Creational\AbstractFactory\Tests;
use DesignPatterns\Creational\AbstractFactory\DigitalProduct;
use DesignPatterns\Creational\AbstractFactory\ProductFactory;
use DesignPatterns\Creational\AbstractFactory\ShippableProduct;
use PHPUnit\Framework\TestCase;
class AbstractFactoryTest extends TestCase
{public function testCanCreateDigitalProduct(){$factory new ProductFactory();$product $factory-createDigitalProduct(150);$this-assertInstanceOf(DigitalProduct::class, $product);}public function testCanCreateShippableProduct(){$factory new ProductFactory();$product $factory-createShippableProduct(150);$this-assertInstanceOf(ShippableProduct::class, $product);}public function testCanCalculatePriceForDigitalProduct(){$factory new ProductFactory();$product $factory-createDigitalProduct(150);$this-assertEquals(150, $product-calculatePrice());}public function testCanCalculatePriceForShippableProduct(){$factory new ProductFactory();$product $factory-createShippableProduct(150);$this-assertEquals(200, $product-calculatePrice());}
}
2、建造者模式Builder
目的
建造者是创建一个复杂对象的一部分接口。
有时候如果建造者对他所创建的东西拥有较好的知识储备这个接口就可能成为一个有默认方法的抽象类又称为适配器。
如果对象有复杂的继承树那么对于建造者来说有一个复杂继承树也是符合逻辑的。
注意建造者通常有一个「流式接口」例如 PHPUnit 模拟生成器。
UML 代码
Director.php
?phpnamespace DesignPatterns\Creational\Builder;use DesignPatterns\Creational\Builder\Parts\Vehicle;/*** Director 类是建造者模式的一部分。 它可以实现建造者模式的接口* 并在构建器的帮助下构建一个复杂的对象** 您也可以注入许多构建器而不是构建更复杂的对象*/
class Director
{public function build(BuilderInterface $builder): Vehicle{$builder-createVehicle();$builder-addDoors();$builder-addEngine();$builder-addWheel();return $builder-getVehicle();}
}
BuilderInterface.php
?phpnamespace DesignPatterns\Creational\Builder;use DesignPatterns\Creational\Builder\Parts\Vehicle;interface BuilderInterface
{public function createVehicle();public function addWheel();public function addEngine();public function addDoors();public function getVehicle(): Vehicle;
}
TruckBuilder.php
?phpnamespace DesignPatterns\Creational\Builder;use DesignPatterns\Creational\Builder\Parts\Vehicle;class TruckBuilder implements BuilderInterface
{/*** var Parts\Truck*/private $truck;public function addDoors(){$this-truck-setPart(rightDoor, new Parts\Door());$this-truck-setPart(leftDoor, new Parts\Door());}public function addEngine(){$this-truck-setPart(truckEngine, new Parts\Engine());}public function addWheel(){$this-truck-setPart(wheel1, new Parts\Wheel());$this-truck-setPart(wheel2, new Parts\Wheel());$this-truck-setPart(wheel3, new Parts\Wheel());$this-truck-setPart(wheel4, new Parts\Wheel());$this-truck-setPart(wheel5, new Parts\Wheel());$this-truck-setPart(wheel6, new Parts\Wheel());}public function createVehicle(){$this-truck new Parts\Truck();}public function getVehicle(): Vehicle{return $this-truck;}
} CarBuilder.php
?phpnamespace DesignPatterns\Creational\Builder;use DesignPatterns\Creational\Builder\Parts\Vehicle;class CarBuilder implements BuilderInterface
{/*** var Parts\Car*/private $car;public function addDoors(){$this-car-setPart(rightDoor, new Parts\Door());$this-car-setPart(leftDoor, new Parts\Door());$this-car-setPart(trunkLid, new Parts\Door());}public function addEngine(){$this-car-setPart(engine, new Parts\Engine());}public function addWheel(){$this-car-setPart(wheelLF, new Parts\Wheel());$this-car-setPart(wheelRF, new Parts\Wheel());$this-car-setPart(wheelLR, new Parts\Wheel());$this-car-setPart(wheelRR, new Parts\Wheel());}public function createVehicle(){$this-car new Parts\Car();}public function getVehicle(): Vehicle{return $this-car;}
}
Parts/Vehicle.php
?phpnamespace DesignPatterns\Creational\Builder\Parts;abstract class Vehicle
{/*** var object[]*/private $data [];/*** param string $key* param object $value*/public function setPart($key, $value){$this-data[$key] $value;}
}
Parts/Truck.php
?phpnamespace DesignPatterns\Creational\Builder\Parts;class Truck extends Vehicle
{
}
Parts/Car.php
?phpnamespace DesignPatterns\Creational\Builder\Parts;class Car extends Vehicle
{
}
Parts/Engine.php
?phpnamespace DesignPatterns\Creational\Builder\Parts;class Engine
{
}
Parts/Wheel.php
?phpnamespace DesignPatterns\Creational\Builder\Parts;class Wheel
{
}
Parts/Door.php
?phpnamespace DesignPatterns\Creational\Builder\Parts;class Door
{
}
测试
Tests/DirectorTest.php
?phpnamespace DesignPatterns\Creational\Builder\Tests;use DesignPatterns\Creational\Builder\Parts\Car;
use DesignPatterns\Creational\Builder\Parts\Truck;
use DesignPatterns\Creational\Builder\TruckBuilder;
use DesignPatterns\Creational\Builder\CarBuilder;
use DesignPatterns\Creational\Builder\Director;
use PHPUnit\Framework\TestCase;class DirectorTest extends TestCase
{public function testCanBuildTruck(){$truckBuilder new TruckBuilder();$newVehicle (new Director())-build($truckBuilder);$this-assertInstanceOf(Truck::class, $newVehicle);}public function testCanBuildCar(){$carBuilder new CarBuilder();$newVehicle (new Director())-build($carBuilder);$this-assertInstanceOf(Car::class, $newVehicle);}
}
3、工厂方法模式Factory Method
目的
对比简单工厂模式的优点是您可以将其子类用不同的方法来创建一个对象。
举一个简单的例子这个抽象类可能只是一个接口。
这种模式是「真正」的设计模式 因为他实现了 S.O.L.I.D 原则中「D」的 「依赖倒置」。
这意味着工厂方法模式取决于抽象类而不是具体的类。 这是与简单工厂模式和静态工厂模式相比的优势。
UML 图 代码
Logger.php
?php
namespace DesignPatterns\Creational\FactoryMethod;
interface Logger
{public function log(string $message);
}
StdoutLogger.php
?php
namespace DesignPatterns\Creational\FactoryMethod;
class StdoutLogger implements Logger
{public function log(string $message){echo $message;}
}
FileLogger.php
?php
namespace DesignPatterns\Creational\FactoryMethod;
class FileLogger implements Logger
{/*** var string*/private $filePath;public function __construct(string $filePath){$this-filePath $filePath;}public function log(string $message){file_put_contents($this-filePath, $message . PHP_EOL, FILE_APPEND);}
}
LoggerFactory.php
?php
namespace DesignPatterns\Creational\FactoryMethod;
interface LoggerFactory
{public function createLogger(): Logger;
}
StdoutLoggerFactory.php
?php
namespace DesignPatterns\Creational\FactoryMethod;
class StdoutLoggerFactory implements LoggerFactory
{public function createLogger(): Logger{return new StdoutLogger();}
}
FileLoggerFactory.php
?php
namespace DesignPatterns\Creational\FactoryMethod;
class FileLoggerFactory implements LoggerFactory
{/*** var string*/private $filePath;public function __construct(string $filePath){$this-filePath $filePath;}public function createLogger(): Logger{return new FileLogger($this-filePath);}
}
测试
Tests/FactoryMethodTest.php
?php
namespace DesignPatterns\Creational\FactoryMethod\Tests;
use DesignPatterns\Creational\FactoryMethod\FileLogger;
use DesignPatterns\Creational\FactoryMethod\FileLoggerFactory;
use DesignPatterns\Creational\FactoryMethod\StdoutLogger;
use DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory;
use PHPUnit\Framework\TestCase;
class FactoryMethodTest extends TestCase
{public function testCanCreateStdoutLogging(){$loggerFactory new StdoutLoggerFactory();$logger $loggerFactory-createLogger();$this-assertInstanceOf(StdoutLogger::class, $logger);}public function testCanCreateFileLogging(){$loggerFactory new FileLoggerFactory(sys_get_temp_dir());$logger $loggerFactory-createLogger();$this-assertInstanceOf(FileLogger::class, $logger);}
}
4、多例模式Multiton
目的
多例模式是指存在一个类有多个相同实例而且该实例都是该类本身。这个类叫做多例类。 多例模式的特点是
多例类可以有多个实例。多例类必须自己创建、管理自己的实例并向外界提供自己的实例。
多例模式实际上就是单例模式的推广。
举例
2 个数据库连接器比如一个是 MySQL 另一个是 SQLite多个记录器一个用于记录调试消息一个用于记录错误
UML 图 代码 Multiton.php
?phpnamespace DesignPatterns\Creational\Multiton;final class Multiton
{const INSTANCE_1 1;const INSTANCE_2 2;/*** var 实例数组*/private static $instances [];/*** 这里私有方法阻止用户随意的创建该对象实例*/private function __construct(){}public static function getInstance(string $instanceName): Multiton{if (!isset(self::$instances[$instanceName])) {self::$instances[$instanceName] new self();}return self::$instances[$instanceName];}/*** 该私有对象阻止实例被克隆*/private function __clone(){}/*** 该私有方法阻止实例被序列化*/private function __wakeup(){}
}
5、对象池模式Pool
目的
对象池模式是一种提前准备1个存放 初始化待用对象 “池”的创建型设计模式而不是一次性创建并使用完成之后销毁。对象池的客户端会向对象池中请求一个对象然后使用这个返回的对象执行相关操作。当客户端使用完毕它将把这个特定类型的工厂对象返回给对象池而不是销毁掉这个对象。
在初始化实例成本高实例化率高可用实例较少的情况下对象池可以极大地提升性能。在创建对象尤其是通过网络时间花销不确定的情况下通过对象池在可期时间内就可以获得所需的对象。
总之对象池模式在需要耗时创建对象方面例如创建数据库连接套接字连接线程和大型图形对象比方字体或位图等使用起来会为你节省宝贵的时间。在特定情况下简单的对象池没有请求外部的资源仅仅将自身保存在内存中或许并不会提升效率和性能甚至会有损性能。
UML 代码
WorkerPool.php
?phpnamespace DesignPatterns\Creational\Pool;class WorkerPool implements \Countable
{/*** var StringReverseWorker[]*/private $occupiedWorkers [];/*** var StringReverseWorker[]*/private $freeWorkers [];public function get(): StringReverseWorker{if (count($this-freeWorkers) 0) {$worker new StringReverseWorker();} else {$worker array_pop($this-freeWorkers);}$this-occupiedWorkers[spl_object_hash($worker)] $worker;return $worker;}public function dispose(StringReverseWorker $worker){$key spl_object_hash($worker);if (isset($this-occupiedWorkers[$key])) {unset($this-occupiedWorkers[$key]);$this-freeWorkers[$key] $worker;}}public function count(): int{return count($this-occupiedWorkers) count($this-freeWorkers);}
}StringReverseWorker.php
?phpnamespace DesignPatterns\Creational\Pool;class StringReverseWorker
{/*** var \DateTime*/private $createdAt;public function __construct(){$this-createdAt new \DateTime();}public function run(string $text){return strrev($text);}
}
测试
Tests/PoolTest.php
?phpnamespace DesignPatterns\Creational\Pool\Tests;use DesignPatterns\Creational\Pool\WorkerPool;
use PHPUnit\Framework\TestCase;class PoolTest extends TestCase
{public function testCanGetNewInstancesWithGet(){$pool new WorkerPool();$worker1 $pool-get();$worker2 $pool-get();$this-assertCount(2, $pool);$this-assertNotSame($worker1, $worker2);}public function testCanGetSameInstanceTwiceWhenDisposingItFirst(){$pool new WorkerPool();$worker1 $pool-get();$pool-dispose($worker1);$worker2 $pool-get();$this-assertCount(1, $pool);$this-assertSame($worker1, $worker2);}
}
6、原型模式Prototype
目的
通过创建一个原型对象然后复制原型对象来避免通过标准的方式创建大量的对象产生的开销(new Foo())。相比正常创建一个对象 会更节省开销。
示例
大数据量 (例如通过 ORM 模型一次性往数据库插入 1,000,000 条数据) 。
UML 图 代码
BookPrototype.php
?phpnamespace DesignPatterns\Creational\Prototype;abstract class BookPrototype
{/*** var string*/protected $title;/*** var string*/protected $category;abstract public function __clone();public function getTitle(): string{return $this-title;}public function setTitle($title){$this-title $title;}
}
BarBookPrototype.php
?phpnamespace DesignPatterns\Creational\Prototype;class BarBookPrototype extends BookPrototype
{/*** var string*/protected $category Bar;public function __clone(){}
}
FooBookPrototype.php
?phpnamespace DesignPatterns\Creational\Prototype;class FooBookPrototype extends BookPrototype
{/*** var string*/protected $category Foo;public function __clone(){}
}
测试
Tests/PrototypeTest.php
?phpnamespace DesignPatterns\Creational\Prototype\Tests;use DesignPatterns\Creational\Prototype\BarBookPrototype;
use DesignPatterns\Creational\Prototype\FooBookPrototype;
use PHPUnit\Framework\TestCase;class PrototypeTest extends TestCase
{public function testCanGetFooBook(){$fooPrototype new FooBookPrototype();$barPrototype new BarBookPrototype();for ($i 0; $i 10; $i) {$book clone $fooPrototype;$book-setTitle(Foo Book No . $i);$this-assertInstanceOf(FooBookPrototype::class, $book);}for ($i 0; $i 5; $i) {$book clone $barPrototype;$book-setTitle(Bar Book No . $i);$this-assertInstanceOf(BarBookPrototype::class, $book);}}
} 7、简单工厂模式Simple Factory
目的
简单工厂模式是一个精简版的工厂模式。
它与静态工厂模式最大的区别是它不是『静态』的。因为非静态所以你可以拥有多个不同参数的工厂你可以为其创建子类。甚至可以模拟Mock它这对编写可测试的代码来讲至关重要。 这也是它比静态工厂模式受欢迎的原因
UML 代码
SimpleFactory.php
?phpnamespace DesignPatterns\Creational\SimpleFactory;class SimpleFactory
{
public function createBicycle(): Bicycle
{
return new Bicycle();
}
}
Bicycle.php
?phpnamespace DesignPatterns\Creational\SimpleFactory;class Bicycle
{public function driveTo(string $destination){return $destination;}
}
用法
$factory new SimpleFactory();$bicycle $factory-createBicycle();$bicycle-driveTo(Paris);
测试
Tests/SimpleFactoryTest.php
?phpnamespace DesignPatterns\Creational\SimpleFactory\Tests;use DesignPatterns\Creational\SimpleFactory\Bicycle;
use DesignPatterns\Creational\SimpleFactory\SimpleFactory;
use PHPUnit\Framework\TestCase;class SimpleFactoryTest extends TestCase
{public function testCanCreateBicycle(){$bicycle (new SimpleFactory())-createBicycle();$this-assertInstanceOf(Bicycle::class, $bicycle);}
}
8、单例模式Singleton
单例模式被公认为是 反面模式为了获得更好的可测试性和可维护性请使用『依赖注入模式』。 在软件工程中一个反面模式Anti-pattern 或 Antipattern指的是在实践中明显出现但又低效或是有待优化的设计模式是用来解决问题的带有共同性的不良方法。它们已经经过研究并分类以防止日后重蹈覆辙并能在研发尚未投产的系统时辨认出来。 Andrew Koenig 在 1995 年造了 Anti-pattern 这个词灵感来自于 GoF 的《设计模式》一书。而这本书则在软件领域引入了 “设计模式”Design Pattern的概念。三年后 Antipattern 因《AntiPatterns》这本书而获得普及而它的使用也从软件设计领域扩展到了日常的社会互动中。按《AntiPatterns》作者的说法可以用至少两个关键因素来把反面模式和不良习惯、错误的实践或糟糕的想法区分开来 行动、过程和结构中的一些重复出现的乍一看是有益的但最终得不偿失的模式 在实践中证明且可重复的清晰记录的重构方案 很多反面模式只相当于是错误、咆哮、不可解的问题、或是可能可以避免的糟糕的实践它们的名字通常都是一些用反话构成的词语。有些时候陷阱Pitfalls或黑色模式Dark Patterns这些不正式的说法会被用来指代各类反复出现的糟糕的解决方法。因此一些有争议的候选的反面模式不会被正式承认。 目的
在应用程序调用的时候只能获得一个对象实例。
例子
数据库连接日志 (多种不同用途的日志也可能会成为多例模式)在应用中锁定文件 (系统中只存在一个 ...)
UML 代码 Singleton.php
?phpnamespace DesignPatterns\Creational\Singleton;final class Singleton
{/*** var Singleton*/private static $instance;/*** 通过懒加载获得实例在第一次使用的时候创建*/public static function getInstance(): Singleton{if (null static::$instance) {static::$instance new static();}return static::$instance;}/*** 不允许从外部调用以防止创建多个实例* 要使用单例必须通过 Singleton::getInstance() 方法获取实例*/private function __construct(){}/*** 防止实例被克隆这会创建实例的副本*/private function __clone(){}/*** 防止反序列化这将创建它的副本*/private function __wakeup(){}
} 测试 Tests/SingletonTest.php
?phpnamespace DesignPatterns\Creational\Singleton\Tests;use DesignPatterns\Creational\Singleton\Singleton;
use PHPUnit\Framework\TestCase;class SingletonTest extends TestCase
{public function testUniqueness(){$firstCall Singleton::getInstance();$secondCall Singleton::getInstance();$this-assertInstanceOf(Singleton::class, $firstCall);$this-assertSame($firstCall, $secondCall);}
}
9、静态工厂模式Static Factory
目的
与抽象工厂模式类似此模式用于创建一系列相关或相互依赖的对象。 『静态工厂模式』与『抽象工厂模式』的区别在于只使用一个静态方法来创建所有类型对象 此方法通常被命名为 factory 或 build 。
例子
Zend FrameworkZend_Cache_Backend 或 _Frontend 使用工厂方法创建缓存后端或前端
UML 代码
StaticFactory.php
?phpnamespace DesignPatterns\Creational\StaticFactory;/*** 注意点1: 记住静态意味着全局状态因为它不能被模拟进行测试所以它是有弊端的* 注意点2: 不能被分类或模拟或有多个不同的实例。*/
final class StaticFactory
{/*** param string $type** return FormatterInterface*/public static function factory(string $type): FormatterInterface{if ($type number) {return new FormatNumber();}if ($type string) {return new FormatString();}throw new \InvalidArgumentException(Unknown format given);}
}
FormatterInterface.php
?phpnamespace DesignPatterns\Creational\StaticFactory;interface FormatterInterface
{
}
FormatString.php
?phpnamespace DesignPatterns\Creational\StaticFactory;class FormatString implements FormatterInterface
{
}
FormatNumber.php
?phpnamespace DesignPatterns\Creational\StaticFactory;class FormatNumber implements FormatterInterface
{
}
测试
Tests/StaticFactoryTest.php
?phpnamespace DesignPatterns\Creational\StaticFactory\Tests;use DesignPatterns\Creational\StaticFactory\StaticFactory;
use PHPUnit\Framework\TestCase;class StaticFactoryTest extends TestCase
{public function testCanCreateNumberFormatter(){$this-assertInstanceOf(DesignPatterns\Creational\StaticFactory\FormatNumber,StaticFactory::factory(number));}public function testCanCreateStringFormatter(){$this-assertInstanceOf(DesignPatterns\Creational\StaticFactory\FormatString,StaticFactory::factory(string));}/*** expectedException \InvalidArgumentException*/public function testException(){StaticFactory::factory(object);}
} 架构模式
10、适配器模式Adapter
目的
将某个类的接口转换成另一个接口以兼容适配器使得原来因为接口不同而无法一起使用的类可以一起工作。 适配器通过将原始接口进行转换给用户提供一个兼容接口。
例子 客户端数据库适配器
使用多个不同的网络服务和适配器来规范数据使得出结果是相同的
UML 代码
BookInterface.php
?phpnamespace DesignPatterns\Structural\Adapter;interface BookInterface
{public function turnPage();public function open();public function getPage(): int;
} Book.php
?phpnamespace DesignPatterns\Structural\Adapter;class Book implements BookInterface
{/*** var int*/private $page;public function open(){$this-page 1;}public function turnPage(){$this-page;}public function getPage(): int{return $this-page;}
}
EBookAdapter.php
?phpnamespace DesignPatterns\Structural\Adapter;/**
* 这里是一个适配器. 注意他实现了 BookInterface,
* 因此你不必去更改客户端代码当使用 Book
*/
class EBookAdapter implements BookInterface
{/*** var EBookInterface*/protected $eBook;/*** param EBookInterface $eBook*/public function __construct(EBookInterface $eBook){$this-eBook $eBook;}/*** 这个类使接口进行适当的转换.*/public function open(){$this-eBook-unlock();}public function turnPage(){$this-eBook-pressNext();}/*** 注意这里适配器的行为 EBookInterface::getPage() 将返回两个整型除了 BookInterface* 仅支持获得当前页所以我们这里适配这个行为** return int*/public function getPage(): int{return $this-eBook-getPage()[0];}
}
EBookInterface.php
?phpnamespace DesignPatterns\Structural\Adapter;interface EBookInterface
{public function unlock();public function pressNext();/*** 返回当前页和总页数像 [10, 100] 是总页数100中的第10页。** return int[]*/public function getPage(): array;
}
Kindle.php
?phpnamespace DesignPatterns\Structural\Adapter;/**
* 这里是适配过的类. 在生产代码中, 这可能是来自另一个包的类一些供应商提供的代码。
* 注意它使用了另一种命名方案并用另一种方式实现了类似的操作
*/
class Kindle implements EBookInterface
{/*** var int*/private $page 1;/*** var int*/private $totalPages 100;public function pressNext(){$this-page;}public function unlock(){}/*** 返回当前页和总页数像 [10, 100] 是总页数100中的第10页。** return int[]*/public function getPage(): array{return [$this-page, $this-totalPages];}
} 测试
Tests/AdapterTest.php
?phpnamespace DesignPatterns\Structural\Adapter\Tests;use DesignPatterns\Structural\Adapter\Book;
use DesignPatterns\Structural\Adapter\EBookAdapter;
use DesignPatterns\Structural\Adapter\Kindle;
use PHPUnit\Framework\TestCase;class AdapterTest extends TestCase
{public function testCanTurnPageOnBook(){$book new Book();$book-open();$book-turnPage();$this-assertEquals(2, $book-getPage());}public function testCanTurnPageOnKindleLikeInANormalBook(){$kindle new Kindle();$book new EBookAdapter($kindle);$book-open();$book-turnPage();$this-assertEquals(2, $book-getPage());}
}
11、桥梁模式Bridge
目的
解耦一个对象使抽象与实现分离这样两者可以独立地变化。
UML 代码
Formatter.php
?phpnamespace DesignPatterns\Structural\Bridge;/**
* 创建格式化接口。
*/
interface FormatterInterface
{public function format(string $text);
} PlainTextFormatter.php
?phpnamespace DesignPatterns\Structural\Bridge;/**
* 创建 PlainTextFormatter 文本格式类实现 FormatterInterface 接口。
*/
class PlainTextFormatter implements FormatterInterface
{/*** 返回字符串格式。*/public function format(string $text){return $text;}
}
HtmlFormatter.php
?phpnamespace DesignPatterns\Structural\Bridge;/**
* 创建 HtmlFormatter HTML 格式类实现 FormatterInterface 接口。
*/
class HtmlFormatter implements FormatterInterface
{/*** 返回 HTML 格式。*/public function format(string $text){return sprintf(p%s/p, $text);}
}
Service.php
?phpnamespace DesignPatterns\Structural\Bridge;/**
* 创建抽象类 Service。
*/
abstract class Service
{/*** var FormatterInterface* 定义实现属性。*/protected $implementation;/*** param FormatterInterface $printer* 传入 FormatterInterface 实现类对象。*/public function __construct(FormatterInterface $printer){$this-implementation $printer;}/*** param FormatterInterface $printer* 和构造方法的作用相同。*/public function setImplementation(FormatterInterface $printer){$this-implementation $printer;}/*** 创建抽象方法 get() 。*/abstract public function get();
}
HelloWorldService.php
?phpnamespace DesignPatterns\Structural\Bridge;/**
* 创建 Service 子类 HelloWorldService 。
*/
class HelloWorldService extends Service
{/*** 定义抽象方法 get() 。* 根据传入的格式类定义来格式化输出 Hello World 。*/public function get(){return $this-implementation-format(Hello World);}
}
测试
Tests/BridgeTest.php
?phpnamespace DesignPatterns\Structural\Bridge\Tests;use DesignPatterns\Structural\Bridge\HelloWorldService;
use DesignPatterns\Structural\Bridge\HtmlFormatter;
use DesignPatterns\Structural\Bridge\PlainTextFormatter;
use PHPUnit\Framework\TestCase;/**
* 创建自动化测试单元 BridgeTest 。
*/
class BridgeTest extends TestCase
{/*** 使用 HelloWorldService 分别测试文本格式实现类和 HTML 格式实* 现类。*/public function testCanPrintUsingThePlainTextPrinter(){$service new HelloWorldService(new PlainTextFormatter());$this-assertEquals(Hello World, $service-get());// 现在更改实现方法为使用 HTML 格式器。$service-setImplementation(new HtmlFormatter());$this-assertEquals(pHello World/p, $service-get());}
}