大话 PHP 设计模式--创建型

前言

随着编程项目经验的增加,从服务于业务逻辑到针对项目的全局设计.认识到设计模式在开发过程中\
的重要性,遵循S.O.L.I.D五大基准原则.它拓展了我的视野,让代码更加灵活,看起来更加富有美感.\
美是构建万物的哲学思想.

我们学习的设计模式分为三类:创建者模式、结构型模式、行为型模式;创建型模式与对象的创建有关;结构型模式处理类或对象的组合;而行为型模式是对类或对象怎样交互和怎样分配职责进行描述;

内容:本文介绍的是PHP设计模式的创建型一篇.包括:单例模式(Singleton),多例模式(Multiton),工厂方法模式(Factory Method),抽象工厂模式(Abstract Factory),简单工厂模式(Simple Factory),原型模式(Prototype),对象池模式(Pool),建造者模式(Builder)

(一)单例模式(Singleton)

  • 定义
    保证一个类只有一个实例,并且提供一个访问它的全局访问点。系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
  • 代码示例
    class Singleton
    {
        /**
        * @var Singleton
        */
        private static $instance;
        /**
        * 不允许从外部调用以防止创建多个实例
        * 要使用单例,必须通过 Singleton::getInstance() 方法获取实例
        */
        private function __construct()
        {
        }
        /**
        * 通过懒加载获得实例(在第一次使用的时候创建)
        */
        public static function getInstance(): Singleton
        {
            if (null === static::$instance) {
                static::$instance = new static();
            }
            return static::$instance;
        }
        /**
        * 防止实例被克隆(这会创建实例的副本)
        */
        private function __clone()
        {
        }
        /**
        * 防止反序列化(这将创建它的副本)
        */
        private function __wakeup()
        {
        }
    }

    *(二)多例模式(Multiton)

  • 定义
    在多例模式中,多例类可以有多个实例,而且多例类必须自己创建、管理自己的实例,并向外界提供自己的实例。1. 通过实例容器保存容器。2. 利用私有构造阻止外部构造。3. 提供getInstantce()方法获取实例.
  • 代码示例  两个对象通过一个类进行多次实例化
    abstract class Multiton { 
        private static $instances = array(); 
        public static function getInstance() { 
            $key = get_called_class() . serialize(func_get_args());
            if (!isset(self::$instances[$key])) { 
                $rc = new ReflectionClass(get_called_class());
                self::$instances[$key] = $rc->newInstanceArgs(func_get_args());
            }
            return self::$instances[$key]; 
        }
        /**
         * 该私有对象阻止实例被克隆
         */
        private function __clone()
        {
        }
        /**
         * 该私有方法阻止实例被序列化
         */
        private function __wakeup()
        {
        }
    } 
    class Hello extends Multiton { 
        public function __construct($string = 'World') { 
            echo "Hello $string\n"; 
        } 
    } 
    class GoodBye extends Multiton { 
        public function __construct($string = 'my', $string2 = 'darling') { 
            echo "Goodbye $string $string2\n"; 
        }
    }
    $a = Hello::getInstance('World'); 
    $b = Hello::getInstance('bob'); 
    // $a !== $b 
    $c = Hello::getInstance('World'); 
    // $a === $c 
    $d = GoodBye::getInstance(); 
    $e = GoodBye::getInstance();
    // $d === $e 
    $f = GoodBye::getInstance('your'); 
    // $d !== $f 

    *(三)工厂方法模式(Factory Method)

  • 定义
    将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类
  • 代码示例 : 小成有一间塑料加工厂(仅生产A类产品);随着客户需求的变化,客户需要生产B类产品。改变原有塑料加工厂的配置和变化非常困难,假设下一次客户需要再发生变化,再次改变将增大非常大的成本;小成决定置办塑料分厂B来生产B类产品。
    abstract class Product{
        public abstract function Show();
    }
    //具体产品A类
    class  ProductA extends  Product{
        public function Show() {
            echo "生产出了产品A";
        }
    }
    //具体产品B类
    class  ProductB extends  Product{
        public function Show() {
            echo "生产出了产品B";
        }
    }
    abstract class Factory{
        public abstract function Manufacture();
    }
    //工厂A类 - 生产A类产品
    class  FactoryA extends Factory{
        public function Manufacture() {
            return new ProductA();
        }
    }
    //工厂B类 - 生产B类产品
    class  FactoryB extends Factory{
        public function Manufacture() {
            return new ProductB();
        }
    }

    *(四)抽象工厂模式(Abstract Factory)

  • 定义
    在不指定具体类的情况下创建一系列相关或依赖对象。 通常创建的类都实现相同的接口。 抽象工厂的客户并不关心这些对象是如何创建的,它只是知道它们是如何一起运行的。
  • 代码示例 : 有两个工厂,A工厂负责运输,B工厂生产数码产品.
    interface Product
    {
        public function calculatePrice(): int;
    }
    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;
        }
    }
    class DigitalProduct implements Product
    {
        /**
         * @var int
         */
        private $price;
        public function __construct(int $price)
        {
            $this->price = $price;
        }
        public function calculatePrice(): int
        {
            return $this->price;
        }
    }
    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);
        }
    }

    *(五)简单工厂模式(Simple Factory)

  • 定义
    简单工厂模式是一个精简版的工厂模式。工厂角色-具体产品-抽象产品
  • 代码示例 : 原文链接:https://www.cnblogs.com/aqsmoke/p/3955310....
    一个农场,要向市场销售水果.农场里有三种水果 苹果、葡萄,我们设想:1、水果有多种属性,每个属性都有不同,但是,他们有共同的地方 | 生长、种植、收货、吃。将来有可能会增加新的水果、我们需要定义一个接口来规范他们必须实现的方法.
    interface fruit{
        /**
         * 生长
         */
        public function grow();
        /**
         * 种植
         */
        public function plant();
        /**
         * 收获
         */
        public function harvest();
        /**
         * 吃
         */
        public function eat();
    }
    class apple implements fruit{
        //苹果树有年龄
        private $treeAge;
        //苹果有颜色
        private $color;
        public function grow(){
            echo "grape grow";
        }
        public function plant(){
            echo "grape plant";
        }
        public function harvest(){
            echo "grape harvest";
        }
        public function eat(){
            echo "grape eat";
        }
        //取苹果树的年龄
        public function getTreeAge(){
            return $this->treeAge;
        }
        //设置苹果树的年龄
        public function setTreeAge($age){
            $this->treeAge = $age;
            return true;
        }
    }
    class grape implements fruit{
        //葡萄是否有籽
        private $seedLess;
        public function grow(){
            echo "apple grow";
        }
        public function plant(){
            echo "apple plant";
        }
        public function harvest(){
            echo "apple harvest";
        }
        public function eat(){
            echo "apple eat";
        }
        //有无籽取值
        public function getSeedLess(){
            return $this->seedLess;
        }
        //设置有籽无籽
        public function setSeedLess($seed){
            $this->seedLess = $seed;
            return true;
        }
    }
    class farmer
    {
        //定义个静态工厂方法
        public static function factory($fruitName){
            switch ($fruitName) {
                case 'apple':
                    return new apple();
                    break;
                case 'grape':
                    return new grape();
                    break;
                default:
                    throw new badFruitException("Error no the fruit", 1);
                    break;
            }
        }
    }
    class badFruitException extends Exception
    {
        public $msg;
        public $errType;
        public function __construct($msg = '' , $errType = 1){
            $this->msg = $msg;
            $this->errType = $errType;
        }  
    }
    /**
     * 获取水果实例化的方法
     */
    try{
        $appleInstance = farmer::factory('apple');
        var_dump($appleInstance);
    }catch(badFruitException $err){
        echo $err->msg . "_______" . $err->errType;
    }

    *(六)原型模式(Prototype)

  • 定义
    相比正常创建一个对象 (new Foo () ),首先创建一个原型,然后克隆它会更节省开销。
  • 代码示例 : 为每一本书设置标题
    abstract class BookPrototype
    {
        /**
        * @var string
        */
        protected $title = 0;
        /**
        * @var string
        */
        protected $category;
        abstract public function __clone();
        public function getTitle(): string
        {
            return $this->title;
        }
        public function setTitle($title)
        {
           $this->title = $title;
        }
    }
    class BarBookPrototype extends BookPrototype
    {
        /**
        * @var string
        */
        protected $category = 'Bar';
        public function __clone()
        {
        }
    }
    class FooBookPrototype extends BookPrototype
    {
        /**
        * @var string
        */
        protected $category = 'Foo';
        public function __clone()
        {
        }
    }
    $fooPrototype = new FooBookPrototype();
    $barPrototype = new BarBookPrototype();
    for ($i = 5; $i < 10; $i++) {
        $book = clone $fooPrototype;
        $book->setTitle('Foo Book No ' . $i);
        var_dump(new FooBookPrototype == $book);
    }
    for ($i = 0; $i < 5; $i++) {
        $book = clone $barPrototype;
        $book->setTitle('Bar Book No ' . $i);
        var_dump(new BarBookPrototype == $book);
    }

    *(七)对象池模式(Pool)

  • 定义
    对象池可以用于构造并且存放一系列的对象并在需要时获取调用。在初始化实例成本高,实例化率高,可用实例不足的情况下,对象池可以极大地提升性能。在创建对象(尤其是通过网络)时间花销不确定的情况下,通过对象池在短期时间内就可以获得所需的对象。
  • 代码示例 
    class Factory {
        protected static $products = array();
        public static function pushProduct(Product $product) {
            self::$products[$product->getId()] = $product;
        }
        public static function getProduct($id) {
            return isset(self::$products[$id]) ? self::$products[$id] : null;
        }
        public static function removeProduct($id) {
            if (array_key_exists($id, self::$products)) {
                unset(self::$products[$id]);
            }
        }
    }
    Factory::pushProduct(new Product('first'));
    Factory::pushProduct(new Product('second'));
    print_r(Factory::getProduct('first')->getId());
    // first
    print_r(Factory::getProduct('second')->getId());
    // second

    *(八)建造者模式(Builder)

  • 定义
    将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
  • 2)代码示例  建造相同标准的卡车和汽车.类似于变形金刚,相同的零件进行不同的组合.
  • 分为 Director 导演者,负责构建、BuilderInterface 构建接口,规范建造标准、TruckBuilder 构建卡车类 CarBuilder 构建汽车类
    Vehicle 零部件公共类、Truck Car Engine Wheel Door 零部件类、DirectorTest 测试类
    class Director
    {
        public function build(BuilderInterface $builder): Vehicle
        {
            $builder->createVehicle();
            $builder->addDoors();
            $builder->addEngine();
            $builder->addWheel();
            return $builder->getVehicle();
        }
    }
    interface BuilderInterface
    {
        public function createVehicle();
        public function addWheel();
        public function addEngine();
        public function addDoors();
        public function getVehicle(): Vehicle;
    }
    class TruckBuilder implements BuilderInterface
    {
        /**
        * @var Truck
        */
        private $truck;
        public function addDoors()
        {
            $this->truck->setPart('rightDoor', new Door());
            $this->truck->setPart('leftDoor', new Door());
        }
        public function addEngine()
        {
            $this->truck->setPart('truckEngine', new Engine());
        }
        public function addWheel()
        {
            $this->truck->setPart('wheel1', new Wheel());
            $this->truck->setPart('wheel2', new Wheel());
            $this->truck->setPart('wheel3', new Wheel());
            $this->truck->setPart('wheel4', new Wheel());
            $this->truck->setPart('wheel5', new Wheel());
            $this->truck->setPart('wheel6', new Wheel());
        }
        public function createVehicle()
        {
            $this->truck = new Truck();
        }
        public function getVehicle(): Vehicle
        {
            return $this->truck;
        }
    }
    class CarBuilder implements BuilderInterface
    {
        /**
        * @var Car
        */
        private $car;
        public function addDoors()
        {
            $this->car->setPart('rightDoor', new Door());
            $this->car->setPart('leftDoor', new Door());
            $this->car->setPart('trunkLid', new Door());
        }
        public function addEngine()
        {
            $this->car->setPart('engine', new Engine());
        }
        public function addWheel()
        {
            $this->car->setPart('wheelLF', new Wheel());
            $this->car->setPart('wheelRF', new Wheel());
            $this->car->setPart('wheelLR', new Wheel());
            $this->car->setPart('wheelRR', new Wheel());
        }
        public function createVehicle()
        {
            $this->car = new Car();
        }
        public function getVehicle(): Vehicle
        {
            return $this->car;
        }
    }
    abstract class Vehicle
    {
        /**
        * @var object[]
        */
        private $data = [];
        /**
        * @param string $key
        * @param object $value
        */
        public function setPart($key, $value)
        {
            $this->data[$key] = $value;
        }
    }
    class Truck extends Vehicle
    {
    }
    class Car extends Vehicle
    {
    }
    class Engine extends Vehicle
    {
    }
    class Wheel extends Vehicle
    {
    }
    class Door extends Vehicle
    {
    }
    class DirectorTest
    {
        public function testCanBuildTruck()
        {
            $truckBuilder = new TruckBuilder();
            return (new Director())->build($truckBuilder);
        }
        public function testCanBuildCar()
        {
            $carBuilder = new CarBuilder();
            return (new Director())->build($carBuilder);
        }
    }
    $directorTest = new DirectorTest();
    var_dump($directorTest->testCanBuildTruck());
    var_dump($directorTest->testCanBuildCar());
本作品采用《CC 协议》,转载必须注明作者和本文链接
上善若水
讨论数量: 2

常用的就单例和工厂

5年前 评论
无名花火

@lovecn 每个模式都有它的实际应用场景,概念记住了,等到用的时候就知道了

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!