设计模式-PHP
Created at 2019-04-23 Updated at 2020-07-29 views
创建型(Creational)
创建型模式专注于如何实例化一个对象或者一组相关对象
简单工厂(Simple Factory)
简单工厂只是为客户端生成一个实例,而不会向客户端公开任何实例化逻辑。
什么时候使用:当创建对象不仅是一些赋值操作,还涉及一些逻辑操作时,将它放在一个专门的工厂中,从而避免代码重复
class productA
{
function __construct()
{
echo 'productA';
}
}
class productB
{
function __construct()
{
echo 'productB';
}
}
class Factory
{
public static function CreateProduct($name)
{
if ($name == 'A') {
return new productA();
} else if ($name == 'B') {
return new productB();
}
}
}
$A = Factory::CreateProduct ('A');
$B = Factory::CreateProduct('B');
}
工厂模式(Factory Method)
意图:定义一个创建对象的接口,让子类自己决定实例化哪一个工厂类,它提供了一种将实例化逻辑委托给子类的方法。
解决的问题:主要解决接口选择的问题。
何时使用:当类中存在一些通用操作,但是所需子类是在运行时在动态决定的情况。换句话说,当客户端无法知道所需的确切子类时。
跟简单工厂的区别:简单工厂只有一个统一的工厂类,而工厂方法是针对每个要创建的对象都会提供一个工厂类,这些工厂都实现了一个工厂基类。
interface Procduct
{
public function getProduct();
}
class ProductA extends Product
{
public function getProduct()
{
echo 'A';
}
}
class ProductB extends Product
{
public function getProduct()
{
echo 'B';
}
}
abstract class Factory
{
abstract static function createProduct();
}
class ProductAFactory extends Factory
{
public static function createProduct()
{
return new ProductA();
}
}
class ProductBFactory extends Factory
{
public static function createProduct()
{
return new ProductB();
}
}
$productA = ProductAFactory::createProduct();
$productA->getProduct();
$productB = ProductBFactory::createProduct();
$productB->getProduct();
抽象工厂模式(Abstract Factory)
工厂中的工厂,该工厂将各个相关/依赖的工厂组合起来,而无需指定他们具体的类
- 什么时候使用:当创建逻辑有点复杂但内部又相互关联时使用
interface Door
{
public function getDescription();
}
class WoodenDoor implements Door
{
public function getDescription()
{
echo 'I am a wooden door';
}
}
class IronDoor implements Door
{
public function getDescription()
{
echo 'I am an iron door';
}
}
interface DoorFittingExpert
{
public function getDescription();
}
class Welder implements DoorFittingExpert
{
public function getDescription()
{
echo 'I can only fit iron doors';
}
}
class Carpenter implements DoorFittingExpert
{
public function getDescription()
{
echo 'I can only fit wooden doors';
}
}
interface DoorFactory
{
public function makeDoor(): Door;
public function makeFittingExpert(): DoorFittingExpert;
}
// Wooden factory to return carpenter and wooden door
class WoodenDoorFactory implements DoorFactory
{
public function makeDoor(): Door
{
return new WoodenDoor();
}
public function makeFittingExpert(): DoorFittingExpert
{
return new Carpenter();
}
}
// Iron door factory to get iron door and the relevant fitting expert
class IronDoorFactory implements DoorFactory
{
public function makeDoor(): Door
{
return new IronDoor();
}
public function makeFittingExpert(): DoorFittingExpert
{
return new Welder();
}
}
$woodenFactory = new WoodenDoorFactory();
$door = $woodenFactory->makeDoor();
$expert = $woodenFactory->makeFittingExpert();
$door->getDescription(); // Output: I am a wooden door
$expert->getDescription(); // Output: I can only fit wooden doors
// Same for Iron Factory
$ironFactory = new IronDoorFactory();
$door = $ironFactory->makeDoor();
$expert = $ironFactory->makeFittingExpert();
$door->getDescription(); // Output: I am an iron door
$expert->getDescription(); // Output: I can only fit iron doors
建造者模式(Builder)
可以创建不同风格的对象,同时避免构造函数污染。适合当某对象可能会有多种风格,或者在创建对象时涉及多个步骤时使用
什么时候使用:当某个对象可能会有多种风格,或者想避免重叠构造器反模式((telescoping constructor anti-pattern) )时使用。与工厂模式的区别是,工厂模式适用于创建过程只有一个步骤的情况,而建造者模式适用于创建过程涉及多个步骤的情况。
重叠构造器反模式(telescoping constructor anti-pattern)
public function __construct($size, $cheese = true, $pepperoni = true, $tomato = false, $lettuce = true) {}构造函数的参数个数很快会变得一发不可收拾,从而要理解参数布局会变得困难。另外假如以后还要添加更多功能的话,该参数列表还会继续增长。
class Burger{
protected $size;
protected $cheese = false;
protected $pepperoni = false;
protected $lettuce = false;
protected $tomato = false;
public function __construct(BurgerBuilder $builder) {
$this->size = $builder->size;
$this->cheese = $builder->cheese;
$this->pepperoni = $builder->pepperoni;
$this->lettuce = $builder->lettuce;
$this->tomato = $builder->tomato;
}
}
class BurgerBuilder {
public $size;
public $cheese = false;
public $pepperoni = false;
public $lettuce = false;
public $tomato = false;
public function __construct(int $size) {
$this->size = $size;
}
public function addPepperoni() {
$this->pepperoni = true;
return $this;
}
public function addLettuce() {
$this->lettuce = true;
return $this;
}
public function addCheese() {
$this->cheese = true;
return $this;
}
public function addTomato() {
$this->tomato = true;
return $this;
}
public function build() : Burger {
return new Burger($this);
}
}
$burger = (new BurgerBuilder(14))
->addPepperoni()
->addLettuce()
->addTomato()
->build();
原型模式(Prototype)
根据某个现有的对象,通过克隆来创建对象
- 什么时候使用:当所需对象和某个现存对象非常相似时,或者当创建操作比克隆花销更大时
class Sheep {
protected $name;
protected $category;
public function __construct(string $name, string $category = 'Mountain Sheep') {
$this->name = $name;
$this->category = $category;
}
public function setName(string $name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function setCategory(string $category) {
$this->category = $category;
}
public function getCategory() {
return $this->category;
}
}
$original = new Sheep("Jolly");
echo $original->getName();
echo $original->getCategory();
// Clone and modify what is required
$cloned = clone $original;
$cloned->setName('Dolly');
echo $cloned->getName();
echo $cloned->getCategory();
单例模式(Singleton)
确保某个类永远只能创建一个对象。
节约系统资源,提高了系统效率,同时也能够严格控制客户对它的访问
final class Singleton
{
private static $instance = null;
/**
* 通过懒加载获得实例(在第一次使用时创建)
*/
public static function getInstance() : Singleton
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct()
{
//构造方法私有化,不允许从外部调用以防止创建多个实例
}
private function __clone()
{
//防止实例被克隆
}
private function __wakeup()
{
//防止反序列化
}
}
结构型(Structural)
结构型模式主要关注对象的组合或者换句话说是实体间如何能够相互使用。
适配器模式(Adapter)
适配器模式允许你在适配器中封装其他不兼容的对象,从而使它们与某些类兼容。
interface perfactMan
{
function cook();
function write();
}
class wife
{
function cook()
{
echo 'cook';
}
}
class man implements perfactMan
{
protected $wife;
function _construct($wife)
{
$this->wife = $wife;
}
function cook()
{
$this->wife->cook();
}
function write()
{
echo 'write';
}
}
$wife = new Wife();
$man = new Man($wife);
$man->cook();
$man->write();
桥接模式(Bridge)
将抽象部分与实现部分相分离。
桥接模式认为组合优于继承。它能将一个层级结构中的实现细节转到位于另一个分离的层级结构的对象中。
interface WebPage{
public function __construct(Theme $theme);
public function getContent();
}
class About implements WebPage{
protected $theme;
public function __construct(Theme $theme) {
$this->theme = $theme;
}
public function getContent() {
return "About page in " . $this->theme->getColor();
}
}
class Careers implements WebPage {
protected $theme;
public function __construct(Theme $theme) {
$this->theme = $theme;
}
public function getContent() {
return "Careers page in " . $this->theme->getColor();
}
}
interface Theme {
public function getColor();
}
class DarkTheme implements Theme {
public function getColor() {
return 'Dark Black';
}
}
class LightTheme implements Theme {
public function getColor() {
return 'Off white';
}
}
$darkTheme = new DarkTheme();
$about = new About($darkTheme);
$careers = new Careers($darkTheme);
echo $about->getContent(); // "About page in Dark Black";
echo $careers->getContent(); // "Careers page in Dark Black";
组合模式(Composite)
组合模式使得客户能以统一的方式对待每个对象
interface Employee {
public function __construct(string $name, float $salary);
public function getName() : string;
public function setSalary(float $salary);
public function getSalary() : float;
public function getRoles() : array;
}
class Developer implements Employee {
protected $salary;
protected $name;
public function __construct(string $name, float $salary) {
$this->name = $name;
$this->salary = $salary;
}
public function getName() : string {
return $this->name;
}
public function setSalary(float $salary) {
$this->salary = $salary;
}
public function getSalary() : float {
return $this->salary;
}
public function getRoles() : array {
return $this->roles;
}
}
class Designer implements Employee {
protected $salary;
protected $name;
public function __construct(string $name, float $salary) {
$this->name = $name;
$this->salary = $salary;
}
public function getName() : string {
return $this->name;
}
public function setSalary(float $salary) {
$this->salary = $salary;
}
public function getSalary() : float {
return $this->salary;
}
public function getRoles() : array {
return $this->roles;
}
}
class Organization {
protected $employees;
public function addEmployee(Employee $employee) {
$this->employees[] = $employee;
}
public function getNetSalaries() : float {
$netSalary = 0;
foreach ($this->employees as $employee) {
$netSalary += $employee->getSalary();
}
return $netSalary;
}
}
// Prepare the employees
$john = new Developer('John Doe', 12000);
$jane = new Designer('Jane', 10000);
// Add them to organization
$organization = new Organization();
$organization->addEmployee($john);
$organization->addEmployee($jane);
echo "Net salaries: " . $organization->getNetSalaries(); // Net Salaries: 22000
装饰器模式(Decorator)
装饰器模式通过将对象封装在装饰器类的对象中,从而你能在运行时动态得修改原对象的行为
interface Coffee {
public function getCost();
public function getDescription();
}
class SimpleCoffee implements Coffee {
public function getCost() {
return 10;
}
public function getDescription() {
return 'Simple coffee';
}
}
class MilkCoffee implements Coffee {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getCost() {
return $this->coffee->getCost() + 2;
}
public function getDescription() {
return $this->coffee->getDescription() . ', milk';
}
}
class WhipCoffee implements Coffee {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getCost() {
return $this->coffee->getCost() + 5;
}
public function getDescription() {
return $this->coffee->getDescription() . ', whip';
}
}
class VanillaCoffee implements Coffee {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getCost() {
return $this->coffee->getCost() + 3;
}
public function getDescription() {
return $this->coffee->getDescription() . ', vanilla';
}
}
$someCoffee = new SimpleCoffee();
echo $someCoffee->getCost(); // 10
echo $someCoffee->getDescription(); // Simple Coffee
$someCoffee = new MilkCoffee($someCoffee);
echo $someCoffee->getCost(); // 12
echo $someCoffee->getDescription(); // Simple Coffee, milk
$someCoffee = new WhipCoffee($someCoffee);
echo $someCoffee->getCost(); // 17
echo $someCoffee->getDescription(); // Simple Coffee, milk, whip
$someCoffee = new VanillaCoffee($someCoffee);
echo $someCoffee->getCost(); // 20
echo $someCoffee->getDescription(); // Simple Coffee, milk, whip, vanilla
依赖注入(Dependency Injection)
减少类和类之间联系,本来是接受各种参数来构造一个对象,现在只接受一个参数,已经实例化的对象
- 容器:
- 降低耦合度
- 实现惰性加载
- 便于管理
class LunTai
{
function roll()
{
echo 'roll';
}
}
class Car
{
protected $luntai;
function __construct($luntai)
{
$this->luntai = $luntai;
}
function run()
{
$this->$luntai->roll();
echo 'run';
}
}
$luntai = new LunTai();
$car = new Car($luntai);
$car->run();
//容器
class Container
{
static $register = [];
static function bind($name, Closure $col)
{
self::$register[$name] = $col;
}
static function make($name)
{
$col = self::$register[$name];
return $col();
}
}
Container::bind('luntai', function () {
return new LunTai()
});
Container::bind('car', function () {
return new Car(Container::make('luntai'));
});
$car = Container::make('car');
$car->run();
// 创建一个容器(后面称作超级工厂)
$container = new Container;
// 向该 超级工厂 添加 超人 的生产脚本
$container->bind('superman', function ($container, $moduleName) {
return new Superman($container->make($moduleName));
});
// 向该 超级工厂 添加 超能力模组 的生产脚本
$container->bind('xpower', function ($container) {
return new XPower;
});
// 同上
$container->bind('ultrabomb', function ($container) {
return new UltraBomb;
});
// ****************** 华丽丽的分割线 **********************
// 开始启动生产
$superman_1 = $container->make('superman', ['xpower']);
$superman_2 = $container->make('superman', ['ultrabomb']);
$superman_3 = $container->make('superman', ['xpower']);
外观模式(Facade)
外观模式为负载子系统提供一个简化接口
class Light
{
fuction turnOn() {
echo '';
}
function turnOff()
{
}
}
class Camera
{
function active()
{
}
funcrion deactive () {
}
}
class Facade
{
protected $light;
protected $camera;
function __construct()
{
$this->light = new Light();
$this->camera = new Camera();
}
function start()
{
$this->light->turnOn();
$this->camera->avtice();
}
function stop()
{
$this->light->turnOff();
$this->camera->deavtice();
}
}
$f = new Facade();
$f->start();
$f->stop();
享元模式(Flyweight)
它能使相似对象间通过尽可能多地共享,以减少内存使用和计算花销
// Anything that will be cached is flyweight.
// Types of tea here will be flyweights.
class KarakTea {
}
// Acts as a factory and saves the tea
class TeaMaker {
protected $availableTea = [];
public function make($preference) {
if (empty($this->availableTea[$preference])) {
$this->availableTea[$preference] = new KarakTea();
}
return $this->availableTea[$preference];
}
}
class TeaShop {
protected $orders;
protected $teaMaker;
public function __construct(TeaMaker $teaMaker) {
$this->teaMaker = $teaMaker;
}
public function takeOrder(string $teaType, int $table) {
$this->orders[$table] = $this->teaMaker->make($teaType);
}
public function serve() {
foreach($this->orders as $table => $tea) {
echo "Serving tea to table# " . $table;
}
}
}
$teaMaker = new TeaMaker();
$shop = new TeaShop($teaMaker);
$shop->takeOrder('less sugar', 1);
$shop->takeOrder('more milk', 2);
$shop->takeOrder('without sugar', 5);
$shop->serve();
// Serving tea to table# 1
// Serving tea to table# 2
// Serving tea to table# 5
代理模式(Proxy)
使用代理模式,一个类可以代表其他类的功能。
interface Door {
public function open();
public function close();
}
class LabDoor implements Door {
public function open() {
echo "Opening lab door";
}
public function close() {
echo "Closing the lab door";
}
}
class Security {
protected $door;
public function __construct(Door $door) {
$this->door = $door;
}
public function open($password) {
if ($this->authenticate($password)) {
$this->door->open();
} else {
echo "Big no! It ain't possible.";
}
}
public function authenticate($password) {
return $password === '$ecr@t';
}
public function close() {
$this->door->close();
}
}
$door = new Security(new LabDoor());
$door->open('invalid'); // Big no! It ain't possible.
$door->open('$ecr@t'); // Opening lab door
$door->close(); // Closing lab door
行为型(Behavioral)
行为型设计模式关注对象之间的通信。
责任链模式(Chain of Responsibility)
它用于创建一个对象链。请求从一端进入,并从一个对象传递到另一个,直至找到适合处理的对象。
abstract class Account {
protected $successor;
protected $balance;
public function setNext(Account $account) {
$this->successor = $account;
}
public function pay(float $amountToPay) {
if ($this->canPay($amountToPay)) {
echo sprintf('Paid %s using %s' . PHP_EOL, $amountToPay, get_called_class());
} else if ($this->successor) {
echo sprintf('Cannot pay using %s. Proceeding ..' . PHP_EOL, get_called_class());
$this->successor->pay($amountToPay);
} else {
throw Exception('None of the accounts have enough balance');
}
}
public function canPay($amount) : bool {
return $this->balance >= $amount;
}
}
class Bank extends Account {
protected $balance;
public function __construct(float $balance) {
$this->balance = $balance;
}
}
class Paypal extends Account {
protected $balance;
public function __construct(float $balance) {
$this->balance = $balance;
}
}
class Bitcoin extends Account {
protected $balance;
public function __construct(float $balance) {
$this->balance = $balance;
}
}
// 创建如下的一个链接
// $bank->$paypal->$bitcoin
//
// 优先使用银行帐户
// 如果银行帐户无法支付再用 paypal
// 如果 paypal 不能支持再用比特币
$bank = new Bank(100); // Bank with balance 100
$paypal = new Paypal(200); // Paypal with balance 200
$bitcoin = new Bitcoin(300); // Bitcoin with balance 300
$bank->setNext($paypal);
$paypal->setNext($bitcoin);
// Let's try to pay using the first priority i.e. bank
$bank->pay(259);
// 输出会是
// ==============
// Cannot pay using bank. Proceeding ..
// Cannot pay using paypal. Proceeding ..:
// Paid 259 using Bitcoin!
命令模式(Command)
它允许你在对象中封装行为。该模式背后的主要思想是:提供将客户与接收者解耦的方法。
// Receiver
class Bulb {
public function turnOn() {
echo "Bulb has been lit";
}
public function turnOff() {
echo "Darkness!";
}
}
interface Command {
public function execute();
public function undo();
public function redo();
}
// Command
class TurnOn implements Command {
protected $bulb;
public function __construct(Bulb $bulb) {
$this->bulb = $bulb;
}
public function execute() {
$this->bulb->turnOn();
}
public function undo() {
$this->bulb->turnOff();
}
public function redo() {
$this->execute();
}
}
class TurnOff implements Command {
protected $bulb;
public function __construct(Bulb $bulb) {
$this->bulb = $bulb;
}
public function execute() {
$this->bulb->turnOff();
}
public function undo() {
$this->bulb->turnOn();
}
public function redo() {
$this->execute();
}
}
class RemoteControl {
public function submit(Command $command) {
$command->execute();
}
}
$bulb = new Bulb();
$turnOn = new TurnOn($bulb);
$turnOff = new TurnOff($bulb);
$remote = new RemoteControl();
$remote->submit($turnOn); // Bulb has been lit!
$remote->submit($turnOff); // Darkness!
迭代器模式(Iterator)
它提供了一种访问对象内所有元素的方法,而避免暴露低层的表示法。
class RadioStation {
protected $frequency;
public function __construct(float $frequency) {
$this->frequency = $frequency;
}
public function getFrequency() : float {
return $this->frequency;
}
}
use Countable;
use Iterator;
class StationList implements Countable, Iterator {
/** @var RadioStation[] $stations */
protected $stations = [];
/** @var int $counter */
protected $counter;
public function addStation(RadioStation $station) {
$this->stations[] = $station;
}
public function removeStation(RadioStation $toRemove) {
$toRemoveFrequency = $toRemove->getFrequency();
$this->stations = array_filter($this->stations, function (RadioStation $station) use ($toRemoveFrequency) {
return $station->getFrequency() !== $toRemoveFrequency;
});
}
public function count() : int {
return count($this->stations);
}
public function current() : RadioStation {
return $this->stations[$this->counter];
}
public function key() {
return $this->counter;
}
public function next() {
$this->counter++;
}
public function rewind() {
$this->counter = 0;
}
public function valid(): bool
{
return isset($this->stations[$this->counter]);
}
}
$stationList = new StationList();
$stationList->addStation(new RadioStation(89));
$stationList->addStation(new RadioStation(101));
$stationList->addStation(new RadioStation(102));
$stationList->addStation(new RadioStation(103.2));
foreach($stationList as $station) {
echo $station->getFrequency() . PHP_EOL;
}
$stationList->removeStation(new RadioStation(89)); // Will remove station 89
中介者模式(Mediator)
中介者模式引入了一个第三方对象(叫中介者 mediator) 来控制两个对象(叫同事 colleagues) 间的交互。它有助于减少彼此通信的类间的耦合性。因为现在它们无需了解对方的实现细节。
// Mediator
class ChatRoom implements ChatRoomMediator {
public function showMessage(User $user, string $message) {
$time = date('M d, y H:i');
$sender = $user->getName();
echo $time . '[' . $sender . ']:' . $message;
}
}
class User {
protected $name;
protected $chatMediator;
public function __construct(string $name, ChatRoomMediator $chatMediator) {
$this->name = $name;
$this->chatMediator = $chatMediator;
}
public function getName() {
return $this->name;
}
public function send($message) {
$this->chatMediator->showMessage($this, $message);
}
}
$mediator = new ChatRoom();
$john = new User('John Doe', $mediator);
$jane = new User('Jane Doe', $mediator);
$john->send('Hi there!');
$jane->send('Hey!');
// Output will be
// Feb 14, 10:58 [John]: Hi there!
// Feb 14, 10:58 [Jane]: Hey!
备忘录模式(Memento)
备忘录模式就是关于用某种方式获取或保存对象当前状态的模式,从而使对象能在稍后顺利恢复。
class EditorMemento {
protected $content;
public function __construct(string $content) {
$this->content = $content;
}
public function getContent() {
return $this->content;
}
}
class Editor {
protected $content = '';
public function type(string $words) {
$this->content = $this->content . ' ' . $words;
}
public function getContent() {
return $this->content;
}
public function save() {
return new EditorMemento($this->content);
}
public function restore(EditorMemento $memento) {
$this->content = $memento->getContent();
}
}
$editor = new Editor();
// Type some stuff
$editor->type('This is the first sentence.');
$editor->type('This is second.');
// Save the state to restore to : This is the first sentence. This is second.
$saved = $editor->save();
// Type some more
$editor->type('And this is third.');
// Output: Content before Saving
echo $editor->getContent(); // This is the first sentence. This is second. And this is third.
// Restoring to last saved state
$editor->restore($saved);
$editor->getContent(); // This is the first sentence. This is second.
观察者模式(Observer)
它在对象间定义了一种依赖关系,从而当某个对象的状态改变后,它的所有依赖对象都将得到通知。
//事件生产者
abstruct class EventGenerator() {
private $observers = [];
function addObserver(Observer $observer)
{
$this->observers[] = $observer;
}
function notify()
{
foreach ($this->$observers as $item) {
$item->update();
}
}
function delObserber($observer)
{
$key = array_search($observer, $this->observers);
array_splice($this->observers, $key, 1);
}
}
//观察者接口
interface Observer
{
function update($event_info = null);
}
//实现观察者逻辑接口
class Observer1 implements Observer
{
function update($event_info = null)
{
echo '给用户发邮件';
}
}
class Observer2 implements Observer
{
function update($event_info = null)
{
echo '给商户发邮件';
}
}
//在主方法中调用
class Order extends EventGenerator
{
function trigger()
{
echo '下单成功';
$this->notify();
}
}
$event = new Order();
$event->addOvserver(new Observer1());
$event->addOvserver(new Observer2());
$event->trigger();
访问者(Visitor)
策略(Strategy)
能让你在运行时选择算法的行为。
状态(State)
模板方法(Template Method)
模板方法定义了某特定算法如何执行的框架,但执行步骤的具体实现则推迟到子类中去完成。