美文网首页
PHP创建对象的几种设计模式

PHP创建对象的几种设计模式

作者: 鸿雁长飞光不度 | 来源:发表于2018-07-01 17:45 被阅读0次

1.单例模式

单例模式.png
class Preferences{

    private $props = array();

    private static $instance;
    //设置为私有不能在外部初始化
    private function __construct()
    {
    }
    public function getProperty($key) {
        return $this->props[$key];
    }
    public function setProperty($key,$val){
        $this->props[$key] = $val;
    }

    public static function getInstance()
    {
//        if (empty(static::$instance)){
//            static::$instance = new Preferences();
//        }
//        return static::$instance;
        //这样写代码会进行类型提示,编译器会自动推断类型
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    //防止clone,设置为私有
    private function __clone()
    {

    }
}

$instance = Preferences::getInstance();

$instance->setProperty('a','1');
$instance->setProperty('b','2');

unset($instance);//下面的值依旧可以用
$instance2 = Preferences::getInstance();
echo $instance2->getProperty('a');
echo $instance2->getProperty('b');

单例模式保证任何时刻都只有一份实例,可以用来对全局设置一些配置,也可以在需要用到全局变量的地方写到单例里面,方便管理。

2.工厂方法模式

一个关于个人事务管理的项目,要求管理预约对象,业务团队和另一个公司建立关系,需要用一个叫做BloggsCal的格式和他们团队交流预约的相关数据,以后还可能有其他的数据格式。

image.png
abstract class ApptEncode
{
    abstract function encode();
}

//Bloggs编码格式
class BloggsApptEncoder extends ApptEncode
{
    function encode()
    {
        echo ' appointment -- bloggs';
    }
}
//Mega编码格式
class MegaApptEncoder extends ApptEncode
{
    function encode()
    {
        echo ' appointment -- Mega';
    }
}

//根据不同的场景获取编码器类,调用相关的编码器生成数据,可以根据传递的参数类型生成
class CommsManager
{
    const BLLOGS = 1;
    const MEGA =2;
    private $mode;

    public function __construct($mode)
    {
        $this->mode = $mode;
    }

    public function getEncoder()
    {
        switch ($this->mode) {
            case (self::BLLOGS):
                return new BloggsApptEncoder();
            default:
                return new MegaApptEncoder();
        }
    }
    //页眉输出
    public function getHeads() {
        switch ($this->mode) {
            case (self::BLLOGS):
                return "bllggs header";
            default:
                return "mega header";
        }
    }
}

通过标志位加switch判断可以在getEncoder方法里面实例化需要的对象,但是如果需要额外的操作,比如增加页眉,switch语句会遍布整个类,多态的使用可以避免if或者switch判断。
把管理类改成下面的形式就是工厂方法模式,工厂方法模式会导致特殊代码重复,不能为创建者创建子类就只是为了实现工厂方法模式,如果没有页眉也页脚这样的话,完全可以用改进前的形式。

工厂方法模式把创建者类与要生产的产品类分离开来,创建者是一个工厂类,其中定义了用于生产产品对象的类方法。如果没有提供默认实现就要创建者类的子类来实例化,一般情况下一个创建者的子类对应一个产品。

abstract class CommsManager
{
   abstract public function getHead();
   abstract public function getFooter();
   abstract public function getEncoder();
}

class BloggsCommsManager extends CommsManager
{
    public function getEncoder()
    {
       return new BloggsApptEncoder();
    }
    public function getFooter()
    {
       return "Bloggs -- footer ";
    }

    public function getHead()
    {
        return "Bloggs -- header ";
    }
}

class MegaCommsManager extends CommsManager
{
    public function getEncoder()
    {
        return new MegaApptEncoder();
    }
    public function getFooter()
    {
        return "mega -- footer ";
    }

    public function getHead()
    {
        return "mega -- header ";
    }
}
image.png

3.抽象工厂模式

如果上面增加了联系人和代办事项两个类别,要求工厂要求创建一系列的类,可以在抽象类的接口声明相关方法,也可以根据传入的参数判断。

抽象工厂模式.png
abstract class ApptEncode
{
    abstract function encode();
}
abstract class TtdEncode
{
    abstract function encode();
}
abstract class ContactEncode
{
    abstract function encode();
}

//Bloggs编码格式
class BloggsApptEncoder extends ApptEncode
{
    function encode()
    {
        echo ' appointment -- bloggs';
    }
}
class BloggsTtdEncoder extends ApptEncode
{
    function encode()
    {
        echo ' ttd -- bloggs';
    }
}
class BloggsContactEncoder extends ApptEncode
{
    function encode()
    {
        echo 'contact -- bloggs';
    }
}
//Mega编码格式
class MegaApptEncoder extends ApptEncode
{
    function encode()
    {
        echo ' appointment -- Mega';
    }
}


//工厂方法模式把创建者类与要生产的产品类分离开来,创建者是一个工厂类,其中定义了用于生产产品对象的类方法。如果没有提供默认实现就要创建者类的子类来实例化
//一般情况下一个创建者的子类对应一个产品。

abstract class CommsManager
{
   abstract public function getHead();
   abstract public function getFooter();
   //创建一系列的对象,不是一个
   abstract public function getApptEncoder();
   abstract public function getThdEncoder();
   abstract public function ContactEncoder();
}
//Mega和这个相似
class BloggsCommsManager extends CommsManager
{
    public function getApptEncoder()
    {
       return new BloggsApptEncoder();
    }
    public function getThdEncoder()
    {
        return new BloggsTtdEncoder();//
    }
    public function ContactEncoder()
    {
        return new BloggsContactEncoder();
    }
    public function getFooter()
    {
       return "Bloggs -- footer ";
    }

    public function getHead()
    {
        return "Bloggs -- header ";
    }
}

4.原型模式

问题.png

可以用抽象工厂模式实现,如下


image.png

但是会产生巨大的平行继承体系,而且不那么灵活。可以原型模式。

class Resource{};
class FishResource extends Resource{};

class Sea{
    public $resource;
    public function __construct(Resource $resource)
    {
        $this->resource = $resource;
    }

    public function __clone()
    {
        // TODO: Implement __clone() method.
        $this->resource = clone $this->resource;
    }
}
class ErathSea extends Sea {}
class MarsSea extends Sea{}

class Forest{}
class EarthForest extends Forest {}
class MarsForest extends Forest{}

class Plains {}
class EarthPlains extends Plains {}
class MarsPlains extends Plains{}

class TerrainFactory
{
    private $sea;
    private $forest;
    private $plains;
    function __construct(Sea $sea, Plains $plains,Forest $forest)
    {
        $this->sea = $sea;
        $this->forest = $forest;
        $this->plains = $plains;
    }

    public function getSea()
    {
        return clone $this->sea;
    }
    public function getForeset()
    {
        return clone $this->forest;
    }
    public function getPlains()
    {
        return clone $this->plains;
    }
}

//如果生成的对象是由其他的对象组成的,代码具有灵活性,假设sea对象都能包含Resource对象(FishResource ,OilResource。

设计模式经常相互包含,比如抽象工厂模式里面包含工厂方法模式。下面是一个单例模式和抽象工厂模式相结合而且常见的例子。

class config {
    static $config = ['codeType' => 'BloggsCommsManager'];
}

class Setting{

    private $props = array();

    private static $instance;
    //设置为私有不能在外部初始化
    private function __construct()
    {
    }
    public static function getInstance()
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    //防止clone,设置为私有
    private function __clone()
    {

    }

    public function getEncoder()
    {
        //假设根据配配置来的
        $class = config::$config['codeType'];
        if (class_exists($class) && $class instanceof CommsManager) {
            return new $class();
        }else{
            return new BloggsCommsManager();
        }
    }
}

$commsManager = Setting::getInstance()->getEncoder();
$commsManager->getApptEncoder()->encode();

相关文章

  • PHP创建对象的几种设计模式

    1.单例模式 单例模式保证任何时刻都只有一份实例,可以用来对全局设置一些配置,也可以在需要用到全局变量的地方写到单...

  • iOS设计模式 ─── 对象创建

    对象创建,就是我们在创建对象时可能会用到的设计模式,这边要根据自己的需求去选择。对象创建有以下几种设计模式:① 原...

  • PHP 设计模式

    PHP的设计模式可以分为三个大类 1. 创建型 在软件工程中,创建型设计模式是处理对象创建机制的设计模式,试图以适...

  • PHP完整实战23种设计模式

    前言设计模式是面向对象的最佳实践实战PHP实战创建型模式创建型 Factory Method(工厂方法)-工厂模式...

  • 设计模式之创建型模式(Kotlin版)

    主要用途: 创建对象 Kotlin中几种最主流的创建型设计模式: 工厂方法模式、抽象工厂模式以及构建者模式。 伴生...

  • JS设计模式深入理解—工厂模式、寄生构造函数模式和稳妥构造函数模

    在学习《JavaScript高级程序设计》(第3版)第六章创建对象时,遇到了针对创建自定义类型对象的几种设计模式。...

  • PHP完整实战23种设计模式

    前言 设计模式是面向对象的最佳实践 实战 PHP实战创建型模式 单例模式 工厂模式 抽象工厂模式 原型模式 建造者...

  • PHP笔记之设计模式

    单态模式 最适合PHP的设计模式1.如果想让一个类,只能有一个对象,不重复创建对象,就先让这个类,不能创建对象,将...

  • 《PHP设计模式大全》系列分享专栏

    php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页 介绍php设计模式中的工厂模式...

  • javascript面向对象与原型

    昨天我们讲了在面向对象中创建对象的几种方式 工厂模式 构造函数模式 工厂模式创建的对象,像工厂一样来创建对象,创建...

网友评论

      本文标题:PHP创建对象的几种设计模式

      本文链接:https://www.haomeiwen.com/subject/uopcuftx.html