項目地址: 戳我
在軟件工程中,建立型設計模式承擔着對象建立的職責,嘗試建立適合程序上下文的對象,對象建立設計模式的產生是因爲軟件工程設計的問題,具體說是向設計中增長複雜度,建立型設計模式解決了程序設計中對象建立的問題。php
建立一系列相關或依賴的對象,而不指定它們的具體類。一般建立的類都實現相同的接口。抽象工廠的客戶端並不關心這些對象是如何建立的,它只知道它們是如何組合在一塊兒的。前端
你能夠在 GitHub 上查看代碼git
Parser.phpgithub
<?php namespace DesignPatterns\Creational\AbstractFactory; interface Parser { public function parse(string $input): array; }
CsvParser.php數據庫
<?php namespace DesignPatterns\Creational\AbstractFactory; class CsvParser implements Parser { const OPTION_CONTAINS_HEADER = true; const OPTION_CONTAINS_NO_HEADER = false; /** * @var bool */ private $skipHeaderLine; public function __construct(bool $skipHeaderLine) { $this->skipHeaderLine = $skipHeaderLine; } public function parse(string $input): array { $headerWasParsed = false; $parsedLines = []; foreach (explode(PHP_EOL, $input) as $line) { if (!$headerWasParsed && $this->skipHeaderLine === self::OPTION_CONTAINS_HEADER) { $headerWasParsed = true; continue; } $parsedLines[] = str_getcsv($line); } return $parsedLines; } }
JsonParser.phpjson
<?php namespace DesignPatterns\Creational\AbstractFactory; class JsonParser implements Parser { public function parse(string $input): array { return json_decode($input, true); } }
ParserFactory.phpsegmentfault
<?php namespace DesignPatterns\Creational\AbstractFactory; class ParserFactory { public function createCsvParser(bool $skipHeaderLine): CsvParser { return new CsvParser($skipHeaderLine); } public function createJsonParser(): JsonParser { return new JsonParser(); } }
生成器的目的是將複雜對象的建立過程(流程)進行抽象,生成器表現爲接口的形式。後端
在特定的狀況下,好比若是生成器對將要建立的對象有足夠多的瞭解,那麼表明生成器的接口 interface
能夠是一個抽象類(也就是說能夠有必定的具體實現,就像衆所周知的適配器模式)。設計模式
若是對象有複雜的繼承樹,理論上建立對象的生成器也一樣具備複雜的繼承樹。緩存
提示:生成器一般具備流暢的接口,推薦閱讀關於PHPUnit
的mock
生成器獲取更好的理解。
你能夠在 GitHub 上找到這些代碼
Director.php
<?php namespace DesignPatterns\Creational\Builder; use DesignPatterns\Creational\Builder\Parts\Vehicle; /** * Director is part of the builder pattern. It knows the interface of the builder * and builds a complex object with the help of the builder * * You can also inject many builders instead of one to build more complex objects */ class Director { public function build(BuilderInterface $builder): Vehicle { $builder->createVehicle(); $builder->addDoors(); $builder->addEngine(); $builder->addWheel(); return $builder->getVehicle(); } }
BuilderInterface.php
<?php namespace 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
<?php namespace 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
<?php namespace 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
<?php namespace 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
<?php namespace DesignPatterns\Creational\Builder\Parts; class Truck extends Vehicle { }
Parts/Car.php
<?php namespace DesignPatterns\Creational\Builder\Parts; class Engine { }
Parts/Engine.php
<?php namespace DesignPatterns\Creational\Builder\Parts; class Engine { }
Parts/Wheel.php
<?php namespace DesignPatterns\Creational\Builder\Parts; class Wheel { }
Parts/Door.php
<?php namespace DesignPatterns\Creational\Builder\Parts; class Door { }
SimpleFactory
的優勢是您能夠子類化它來實現建立對象的不一樣方法。
對於簡單的狀況,這個抽象類可能只是一個接口。
這個模式是一個 "真正" 的設計模式,由於它遵循了依賴反轉原則 Dependency Inversion Principle
衆所周知這個 "D"
表明了真正的面向對象程序設計。
它意味着工廠方法類依賴於類的抽象,而不是具體將被建立的類,這是工廠方法模式與簡單工廠模式和靜態工廠模式最重要的區別。
你能夠在 GitHub 上找到這些代碼
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); } }
多例模式已經被考慮列入到反模式中!請使用依賴注入得到更好的代碼可測試性和可控性!
使類僅有一個命名的對象的集合可供使用,像單例模式可是有多個實例。
MySQL
,另外一個鏈接SQLite
你能夠在 GitHub 上找到這些代碼
Multiton.php
<?php namespace DesignPatterns\Creational\Multiton; final class Multiton { const INSTANCE_1 = '1'; const INSTANCE_2 = '2'; /** * @var Multiton[] */ private static $instances = []; /** * this is private to prevent from creating arbitrary 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]; } /** * prevent instance from being cloned */ private function __clone() { } /** * prevent instance from being unserialized */ private function __wakeup() { } }
對象池設計模式 是建立型設計模式,它會對新建立的對象應用一系列的初始化操做,讓對象保持當即可以使用的狀態 - 一個存放對象的 「池子」 - 而不是對對象進行一次性的的使用(建立並使用,完成以後當即銷燬)。對象池的使用者會對對象池發起請求,以指望獲取一個對象,並使用獲取到的對象進行一系列操做,當使用者對對象的使用完成以後,使用者會將由對象池的對象建立工廠建立的對象返回給對象池,而不是用完以後銷燬獲取到的對象。
對象池在某些狀況下會帶來重要的性能提高,好比耗費資源的對象初始化操做,實例化類的代價很高,但每次實例化的數量較少的狀況下。對象池中將被建立的對象會在真正被使用時被提早建立,避免在使用時讓使用者浪費對象建立所需的大量時間(好比在對象某些操做須要訪問網絡資源的狀況下)從池子中取得對象的時間是可預測的,但新建一個實例所需的時間是不肯定。
總之,對象池會爲你節省寶貴的程序執行時間,好比像數據庫鏈接,socket
鏈接,大量耗費資源的表明數字資源的對象,像字體或者位圖。不過,在特定狀況下,簡單的對象建立池(沒有請求外部的資源,僅僅將自身保存在內存中)或許並不會提高效率和性能,這時候,就須要使用者酌情考慮了。
你能夠在 GitHub 上找到這些代碼
WorkerPool.php
<?php namespace 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
<?php namespace DesignPatterns\Creational\Pool; class StringReverseWorker { /** * @var \DateTime */ private $createdAt; public function __construct() { $this->createdAt = new \DateTime(); } public function run(string $text) { return strrev($text); } }
經過建立一個原型對象,而後複製原型對象來避免經過標準的方式建立大量的對象產生的開銷(new Foo()
)。
ORM
獲取1,000,000行數據庫記錄而後建立每一條記錄對應的對象實體)你能夠在 GitHub 上找到這些代碼
BookPrototype.php
<?php namespace 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
<?php namespace DesignPatterns\Creational\Prototype; class BarBookPrototype extends BookPrototype { /** * @var string */ protected $category = 'Bar'; public function __clone() { } }
FooBookPrototype.php
<?php namespace DesignPatterns\Creational\Prototype; class FooBookPrototype extends BookPrototype { /** * @var string */ protected $category = 'Foo'; public function __clone() { } }
它與靜態工廠不一樣,由於它不是靜態的。所以,能夠有多個參數化的工廠,能夠子類化它,也能夠模擬它。它老是比靜態工廠更受歡迎!
你能夠在 GitHub 上找到這些代碼
SimpleFactory.php
<?php namespace DesignPatterns\Creational\SimpleFactory; class SimpleFactory { public function createBicycle(): Bicycle { return new Bicycle(); } }
Bicycle.php
<?php namespace DesignPatterns\Creational\SimpleFactory; class Bicycle { public function driveTo(string $destination) { } }
$factory = new SimpleFactory(); $bicycle = $factory->createBicycle(); $bicycle->driveTo('Paris');
使應用中只存在一個對象的實例,而且使這個單實例負責全部對該對象的調用。
你能夠在 GitHub 上找到這些代碼
Singleton.php
<?php namespace DesignPatterns\Creational\Singleton; final class Singleton { /** * @var Singleton */ private static $instance; /** * gets the instance via lazy initialization (created on first usage) */ public static function getInstance(): Singleton { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } /** * is not allowed to call from outside to prevent from creating multiple instances, * to use the singleton, you have to obtain the instance from Singleton::getInstance() instead */ private function __construct() { } /** * prevent the instance from being cloned (which would create a second instance of it) */ private function __clone() { } /** * prevent from being unserialized (which would create a second instance of it) */ private function __wakeup() { } }
和抽象工廠相似,靜態工廠模式用來建立一系列互相關聯或依賴的對象,和抽象工廠模式不一樣的是靜態工廠模式只用一個靜態方法就解決了全部類型的對象建立,一般被命名爲 Factory
或者 Generators
zend_cache_
後端或 _Frontend
使用工廠方法建立緩存後端和前端你能夠在 GitHub 上找到這些代碼
StaticFactory.php
<?php namespace DesignPatterns\Creational\StaticFactory; /** * Note1: Remember, static means global state which is evil because it can't be mocked for tests * Note2: Cannot be subclassed or mock-upped or have multiple different instances. */ final class StaticFactory { /** * @param string $type * * @return Formatter */ public static function factory(string $type): Formatter { if ($type == 'number') { return new FormatNumber(); } elseif ($type == 'string') { return new FormatString(); } throw new \InvalidArgumentException('Unknown format given'); } }
Formatter.php
<?php namespace DesignPatterns\Creational\StaticFactory; interface Formatter { public function format(string $input): string; }
FormatString.php
<?php namespace DesignPatterns\Creational\StaticFactory; class FormatString implements Formatter { public function format(string $input): string { return $input; } }
FormatNumber.php
<?php namespace DesignPatterns\Creational\StaticFactory; class FormatNumber implements Formatter { public function format(string $input): string { return number_format($input); } }