PHP设计模式

news2024/9/21 11:02:05

目录

一、使用设计模式目的

二、设计模式的七大原则

三、创建型模式(构建型模式)

1、单例模式

代码实例

2、工厂模式

2.1、工厂模式——简单工厂模式

简单工厂模式的代码实例

2.2、工厂模式——工厂方法模式

工厂方法模式的代码实例

 2.3、工厂模式——抽象工厂模式

3、原型模式

原型模式的代码实例

浅拷贝

深拷贝

4、建造者模式

四、结构型模式

适配器模式

桥接模式

装饰模式

组合模式

外观模式

享元模式

代理模式

五、行为型模式

模版方法模式

命令模式

访问者模式

迭代器模式(Iterator)(生成器模式(generator)是迭代器的一种,即迭代器的实现)

观察者模式

中介者模式

备忘录模式、

解释器模式(Interpreter)

状态模式

策略模式

职责链模式(责任链模式)


一、使用设计模式目的

  1. 重用性 (相同功能的代码,不用多次编写)
  2. 可读性 (编程规范性, 便于其他程序员的阅读和理解)
  3. 可扩展性 (当需要增加新的功能时,非常的方便,称为可维护)
  4. 可靠性 (当我们增加新的功能后,对原来的功能没有影响)
  5. 使程序呈现高内聚,低耦合的特性

二、设计模式的七大原则

  1. 单一职责原则:一个类应该只负责一项职责
  2. 接口隔离原则:一个类对另一个类的依赖应该建立在最小的接口上。客户端不应该依赖它不需要的接口
  3. 依赖倒转(倒置)原则:对抽象进行编程,不要对实现进行编程。程序要依赖于抽象接口,不要依赖于具体实现
  4. 里氏替换原则:子类可以扩展父类的功能,但不能改变原有父类的功能
  5. 开闭原则:又叫开放封闭原则。对扩展开发,对修改关闭
  6. 迪米特法则:又叫最少知识原则。一个类对于其他类知道的越少越好
  7. 合成复用原则:又叫组合/聚合复用原则。通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

三、创建型模式(构建型模式)

  • 1、单例模式

 

单例模式的主要特点是【三私一公】

  1.  私有的静态成员变量(用来保存类的唯一实例)
  2.  私有的构造函数,防止外部程序new一个对象从而失去单例的意义
  3.  私有的克隆函数,防止对象被克隆
  4.  公共的静态方法(通常命名为getInstance),从而返回唯一实例的一个引用。

代码实例

<?php

namespace App\Services;

class DanLiService
{
    private static $instance = null;

    private function __construct()
    {
    }

    private function __clone()
    {
        // TODO: Implement __clone() method.
    }

    public static function getInstance()
    {
        if(empty( self::$instance )){
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function testOne()
    {
        return '实现1';
    }

    public function testTwo()
    {
        return '实现2';
    }

}

$obj = DanLiService::getInstance();
print_r($obj->testOne());
print_r($obj->testTwo());

2、工厂模式

        工厂模式一共分3三种:简单工厂模式、工厂方法模式、抽象工厂模式

        在平时写代码过程中,构建对象最常用的方式是 new 一个对象。这属于一种硬编码。每 new 一个对象,相当于调用者就知道了一个类,增加了类与类之间的联系,不利于程序的松耦合。其实构建过程可以被封装起来,工厂模式便是用于封装对象的设计模式。

  • 2.1、工厂模式——简单工厂模式

例如:

        当我们需要一个苹果时,我们需要知道苹果的构造方法,需要一个梨子时,需要知道梨子的构造方法。

        更好的实现方式是有一个水果工厂,我们告诉工厂需要什么种类的水果,水果工厂将我们需要的水果制造出来给我们就可以了。这样我们就无需知道苹果、梨子是怎么种出来的,只用和水果工厂打交道即可。

  • 简单工厂模式的代码实例

/**
 * 水果工厂类
 */
class FruitFactory
{
    /**
     * 通知不同水果的生产车间
     * @param string    $name   [车间名字]
     * @return object
     */
    public static function noticeWorkShop( $name )
    {
        switch($name){
            //苹果
            case 'apple':
                return new Apple();
            //梨
            case 'pear':
                return new Pear();
            default:
                throw new \Exception( '抱歉!我们工厂不生产该种类水果。' );
        }
    }
}

/**
 * 苹果车间
 */

class Apple implements Product
{
    public function __construct()
    {
    }

    public function eat()
    {
        // TODO: Implement sound() method.
        echo '我是苹果';
    }
}

/**
 * 梨车间
 */

class Pear implements Product
{
    public function __construct()
    {
    }

    public function eat()
    {
        // TODO: Implement sound() method.
        echo '我是梨';
    }
}


/**
 * 水果产品接口类,该类中定义的方法,都是子类所必须实现的方法
 */
interface Product
{
    /**
     * @return mixed
     */
    public function eat();
}

//调用实例
try{
  $product = FruitFactory::noticeWorkShop('apple');
  $obj = $product->eat();
  print_r($obj);die;
}catch(\Exception $e) {
  echo $e->getMessage();
}
  • 2.2、工厂模式——工厂方法模式

工厂方法模式是简单工厂的升级版,在原有的基础上对工厂进行一个抽象的升级,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。

  • 工厂方法模式的代码实例

/**
 * 苹果工厂类,专门负责加工苹果
 */

class AppleFactory
{
    public function __construct()
    {
    }

    public function create(){
        return new Apple();
    }
}


/**
 * 梨工厂,专门负责加工梨
 */

class PearFactory
{
    public function __construct()
    {
    }

    public function create()
    {
        return new Pear();
    }
}

//调用实例
try{
    //调用苹果工厂
    $appleFactory = new AppleFactory();
    $appleObj = $appleFactory->create();
    $appleObj->eat();
    //调用梨工厂
    $pearFactory = new PearFactory();
    $pearObj = $pearFactory->create();
    $pearObj->eat();
    die;
}catch(\Exception $e) {
  echo $e->getMessage();
}

        有没有发现上述代码和直接 new 出Apple对象和Pear对象有什么区别?感觉上没什么区别。不过上文提到了工厂是为了减少类与类之间的耦合,让调用者尽可能少的和其他类打交道。用简单工厂模式,我们只需要知道 FruitFactory,无需知道 Apple 、Pear 类,很容易看出耦合度降低了。但用工厂方法模式,调用者虽然不需要和 Apple 、Pear 类打交道了,但却需要和 AppleFactory、PearFactory 类打交道。有几种水果就需要知道几个工厂类,耦合度完全没有下降,甚至还增加了代码量!

        还是有些优点的:

  1. 当某个产品构建相当复杂时,工厂将构建过程封装起来,调用者可以很方便的使用。
  2. 当生产的水果产品越来越多时,工厂类不会变成超级类,工厂类会越来越多,但不会越来越大,不会变得臃肿,这就符合【单一职责原则】
  •  2.3、工厂模式——抽象工厂模式

抽象工厂模式:是工厂方法模式的进一步优化 

/**
 * 抽象工厂接口
 */
interface InterfaceFactory
{
    /**
     * @return mixed
     */
    public function create();
}
/**
 * 苹果工厂类,继承工厂接口
 */

class AppleFactory implements InterfaceFactory
{
    public function create(){
        return new Apple();
    }
}

/**
 * 梨工厂类,继承工厂接口
 */

class PearFactory implements InterfaceFactory
{

    public function create()
    {
        return new Pear();
    }
}

此时,调用者可以将 AppleFactory 和 PearFactory 统一作为 InterfaceFactory 对象使用

//调用者
try{
    $appleFactory = new AppleFactory();
    $objApple = $appleFactory->create();
    $objApple->eat();
}catch(\Exception $e) {
    echo $e->getMessage();
}
  1.  由于客户端只和 InterfaceFactory 打交道了,调用的是接口中的方法,使用时根本不需要知道是在哪个具体工厂中实现的这些方法,这就使得替换工厂变得非常容易。
  2. 抽象工厂模式很好的发挥了开闭原则、依赖倒置原则,但缺点是抽象工厂模式太重了,如果 InterfaceFactory 接口需要新增功能,则会影响到所有的具体工厂类。使用抽象工厂模式,替换具体工厂时只需更改一行代码,但要新增抽象方法则需要修改所有的具体工厂类。所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求,不适合新增功能这样的纵向扩展。

3、原型模式

  • 原型模式(Prototype Pattern):与工厂模式类似,都是用来创建对象的。原型模式是利用克隆来生成一个大对象,减少创建(new)时的初始化等操作占用开销,原型模式仅需内存拷贝
  • 为什么需要原型模式?
  1. 有些时候,我们需要创建多个类似的大对象。如果直接通过new对象,开销很大,而且new完还得进行重复的初始化工作。可能把初始化工作封装起来的,但是对于系统来说,你封不封装,初始化工作还是要执行。
  2. 原型模式则不同,原型模式是先创建好一个原型对象,然后通过clone这个原型对象来创建新的对象,这样就免去了重复的初始化工作,系统仅需内存拷贝即可。
  • 原型模式的代码实例

定义一个原型接口 

interface Prototype{
    //浅拷贝
    public function shallowCopy();

    //深拷贝
    public function deepCopy();
}

定义一个具体原型

class ConcretePrototype implements Prototype
{
    private $_name;
    public function __construct($name)
    {
        $this->_name = $name;
    }

    public function setName($name)
    {
        $this->_name = $name;
    }
    public function getName()
    {
        return $this->_name;
    }


    //浅拷贝
    public function shallowCopy()
    {
        // TODO: Implement shallowCopy() method.
        return clone $this;
    }

    //深拷贝
    public function deepCopy()
    {
        // TODO: Implement deepCopy() method.
        $serializeObj = serialize($this);
        $cloneObj = unserialize($serializeObj);
        return clone $cloneObj;
    }

}

定义一个用户测试原型

class Demo{
    public $string;
}

class UserPrototype
{
    //浅拷贝
    public function shallow()
    {
        $demo = new Demo();
        $demo->string = "susan";

        $object_shallow_first = new ConcretePrototype($demo);
        $object_shallow_second = $object_shallow_first->shallowCopy();


        var_dump($object_shallow_first->getName());
        echo '<br/>';
        var_dump($object_shallow_second->getName());
        echo '<br/>';

        $demo->string = "sacha";
        var_dump($object_shallow_first->getName());
        echo '<br/>';
        var_dump($object_shallow_second->getName());
        echo '<br/>';

    }

    //深拷贝
    public function deep()
    {
        $demo = new Demo();
        $demo->string = "Siri";

        $object_deep_first = new ConcretePrototype($demo);
        $object_deep_second = $object_deep_first->deepCopy();

        var_dump($object_deep_first->getName());
        echo '<br/>';
        var_dump($object_deep_second->getName());
        echo '<br/>';

        $demo->string = "Demo";
        var_dump($object_deep_first->getName());
        echo '<br/>';
        var_dump($object_deep_second->getName());
        echo '<br/>';

    }
}

调用

try{
    $user = new UserPrototype();
    $user->shallow();
    echo "</BR>";
    $user->deep();;
}catch(\Exception $e) {
    echo $e->getMessage();
}

调用测试结果

object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "susan" }
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "susan" }
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "sacha" }
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "sacha" }

object(App\Services\Demo)#1236 (1) { ["string"]=> string(4) "Siri" }
object(App\Services\Demo)#1237 (1) { ["string"]=> string(4) "Siri" }
object(App\Services\Demo)#1236 (1) { ["string"]=> string(4) "Demo" }
object(App\Services\Demo)#1237 (1) { ["string"]=> string(4) "Siri" }

浅拷贝

赋值时引用赋值,相当于取了一个别名。对其中一个修改,会影响另一个, 对象作为参数传递时,也是引用传递 

深拷贝

赋值时值完全复制,完全的copy,对其中一个作出改变,不会影响另一个

4、建造者模式

核心思想是将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式

/**
 * 抽象接口
 */
interface InterfaceBuilder
{
    //创建车辆
    public function createVehicle();

    //添加车门
    public function addDoors();

    //添加引擎
    public function addEngine();

    //添加车轮
    public function addWheel();

    //获取车辆
    public function getVehicle();

}

 实现所有方法的自行车类

class BikeBuilder implements InterfaceBuilder
{
    protected $bike;

    public function createVehicle()
    {
        $this->bike[] = '创建自行车建造任务';
    }

    public function addDoors()
    {
        $this->bike[] = '建造了车门';
    }

    public function addEngine()
    {
        $this->bike[] = null;
    }

    public function addWheel()
    {
        $this->bike[] = '建造了车轮';
    }

    public function getVehicle()
    {
       return $this->bike;
    }
}

 实现所有方法的轿车类

class CarBuilder implements InterfaceBuilder
{
    protected $car;

    public function createVehicle()
    {
        $this->car[] = '创建小轿车建造任务';
    }

    public function addDoors()
    {
        $this->car[] = '建造了车门';
    }

    public function addEngine()
    {
        $this->car[] = '建造了引擎发动机';
    }

    public function addWheel()
    {
        $this->car[] = '建造了车轮';
    }

    public function getVehicle()
    {
        return $this->car;
    }
}

 按照实际需要,分别调用Bike类和Car类,实现所有功能聚合

class Index
{
    public $vecicle;

    public function getVe($type = 1)
    {
        if ($type == 1) { //Bike
            $this->vecicle = new BikeBuilder();
        } else if ($type == 2) { //Car
            $this->vecicle = new CarBuilder();
        }
        $this->vecicle->createVehicle();
        $this->vecicle->addDoors();
        $this->vecicle->addEngine();
        $this->vecicle->addWheel();
        $this->vecicle->getVehicle();

        return $this->vecicle;
    }

}

四、结构型模式

  • 适配器模式

  • 桥接模式

  • 装饰模式

  • 组合模式

  • 外观模式

  • 享元模式

  • 代理模式

五、行为型模式

  • 模版方法模式

  • 命令模式

  • 访问者模式

  • 迭代器模式(Iterator)(生成器模式(generator)是迭代器的一种,即迭代器的实现)

  • 观察者模式

  • 中介者模式

  • 备忘录模式、

  • 解释器模式(Interpreter)

  • 状态模式

  • 策略模式

  • 职责链模式(责任链模式)
     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/172280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java开发环境配置及问题排查

Java程序必须运行在JVM之上&#xff0c;所以&#xff0c;我们第一件事情就是安装JDK。 JDK(Java Development Kit)&#xff0c;是Java开发工具包&#xff0c;它提供了Java的开发环境(提供了编译器javac等工具&#xff0c;用于将java文件编译为class文件)和运行环境(提 供了JVM…

Java内存模型和线程安全

Java内存模型和线程安全Java内存模型引言volatile关键字synchronized关键字Java线程Java线程安全synchronized锁优化锁优化技巧列举自旋锁锁消除锁粗化具体实现轻量级锁偏向锁Java内存模型 引言 对于多核处理器而言,每个核都会有自己单独的高速缓存,又因为这多个处理器共享同一…

JavaWeb-会话技术

JavaWeb-会话技术 1&#xff0c;会话跟踪技术的概述 对于会话跟踪这四个词&#xff0c;我们需要拆开来进行解释&#xff0c;首先要理解什么是会话&#xff0c;然后再去理解什么是会话跟踪: 会话:用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff…

反射机制.

文章目录概述两个疑问关于java.lang.Class的理解获取Class实例的方式哪些类型可以有Class对象了解类的加载器掌握加载配置文件的另一种方式创建运行时类的对象体会动态性获取运行时类的完整结构调用运行时类的制定结构每日一考动态代理概述 1、反射是动态语言的关键 2、动态语…

使用Docker打包镜像并发布

1、docker介绍 Docker 是一个开源的应用容器引擎&#xff0c;以镜像的形式进行发布。docker的图标是一个大鲸鱼驮着许多集装箱在海上航行。大鲸鱼就是docker&#xff0c;集装箱就是一个个容器。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口&#xff0c;每个容器都…

高级Spring之BeanFactory 与 ApplicationContext 的区别

ApplicationContext接口 SpringBootApplication public class A01 {private static final Logger log LoggerFactory.getLogger(A01.class);public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {//启动SpringBoot程序…

Python Scipy 显著性检验

Scipy 显著性检验显著性检验&#xff08;significance test&#xff09;就是事先对总体&#xff08;随机变量&#xff09;的参数或总体分布形式做出一个假设&#xff0c;然后利用样本信息来判断这个假设&#xff08;备择假设&#xff09;是否合理&#xff0c;即判断总体的真实情…

Linux基本功系列之userdel命令实战

春节马上要到了&#xff0c;大街上到处都是张灯结彩&#xff0c;喜气洋洋的景象&#xff0c;你们那里也开始了吗&#xff1f; 文章目录一. userdel命令概述二. 语法格式及常用选项语法格式及常用参数三. 参考案例3.1 删除用户但不删除家目录等相关的文件3.2 把用户彻底删除3.3 …

【Linux05-进程控制】进程创建、进程等待、进程退出、进程程序替换(附简易shell实现)

前言 本期分享进程控制的内容。 博主水平有限&#xff0c;不足之处望请斧正&#xff01; 进程的控制主要分为四点&#xff1a; 进程创建进程退出进程等待进程程序替换 进程创建 怎么创建 通过fork创建。 #fork 是什么 创建子进程的函数。&#xff08;使用已经介绍过&am…

Python基础学习 -- 概念

一、变量python的变量定义起来比较随意&#xff0c;不用定义数据类型a123b"123"系统会自动识别a为数值&#xff0c;b为字符串二、关键字定义变量名字的时候&#xff0c;要避开下面的关键字&#xff0c;但是可以通过大小写区分&#xff0c;as123;#错误定义As123;print…

阿里云服务器ECS

云服务器 ECS云服务器ECS&#xff08;Elastic Compute Service&#xff09;是一种简单高效、处理能力可弹性伸缩的计算服务。帮助您构建更稳定、安全的应用&#xff0c;提升运维效率&#xff0c;降低IT成本&#xff0c;使您更专注于核心业务创新。为什么选择云服务器ECS选择云服…

音频如何分割成两段音频?这些实用方法值得收藏

有些时候&#xff0c;我们从网上下载的音频素材可能会出现体积较大、播放时间长等情况&#xff0c;而我们却只需要其中的一小段。这个时候我们就需要借助一些音频分割软件来将重要的音频片段提取出来&#xff0c;从而有助于缩小音频文件的占比以及存储。那么如何如何分割音频呢…

JVM进修之路(一)程序计数器与虚拟机栈

JVM 定义&#xff1a;JVM:Java Virtual Machine&#xff0c;也就是Java运行时所需要的环境&#xff08;Java二进制字节码运行时所需要的环境&#xff09; 好处&#xff1a; 1.java代码一次编写&#xff0c;跨平台运行 2.自动内存管理&#xff0c;垃圾回收 3.数组下标越界检查 4…

千锋Node.js学习笔记

千锋Node.js学习笔记 文章目录千锋Node.js学习笔记写在前面1. 认识Node.js2. NVM3. NPM4. NRM5. NPX6. 模块/包与CommonJS7. 常用内置模块1. url2. querystring3. http4. 跨域jsonpcorsmiddleware&#xff08;http-proxy-middleware&#xff09;5. 爬虫6. events7. File System…

Mysql常用命令练习(一)

Mysql常用命令练习&#xff08;一&#xff09;一、数据库的三层结构二、数据库2.1、创建数据库2.2、查看、删除数据库2.3、备份和恢复数据库三、表3.1、创建表mysql常用的数据类型(列类型)创建表查看表查看表结构练习3.2、修改表修改表名修改表的字符集添加列修改列删除列练习3…

轻量级网络模型ShuffleNet

在学习ShuffleNet内容前需要简单了解卷积神经网络和MobileNet的相关内容&#xff0c;大家可以去看我之前的一篇博客MobileNet发展脉络&#xff08;V1-V2-V3&#xff09;&#xff0c;&#x1f197;&#xff0c;接下来步入正题~卷积神经网络被广泛应用在图像分类、目标检测等视觉…

易盾sdk引起项目的整体耗时问题?

大家好&#xff1a; 我是烤鸭。今年年初的时候&#xff0c;项目接入易盾sdk之后&#xff0c;随着接口调用次数增多(用到易盾sdk的接口)&#xff0c;项目整体性能变差。写篇文章做个复盘记录&#xff0c;其实同事已经写过了&#xff0c;我借鉴部分再拓展一些。 问题描述 突然收…

【JavaEE初阶】第五节.多线程 ( 基础篇 ) 线程安全问题(上篇)

目录 文章目录 前言 一、线程安全的概述 1.1 什么是线程安全问题 1.2 存在线程安全问题的实例 二、线程安全问题及其解决办法 2.1 案例分析 2.2 造成线程不安全的原因 2.3 线程加锁操作解决原子性 问题 &#xff1b; 2.3.1 什么是加锁 2.3.2 使用 synchronized关键字…

爆品跟卖商家必读:2023年快速入局TikTok选品5大关键

TikTok商业进程一直有在发展&#xff0c;开启东南亚小店&#xff0c;美国小店内邀……有吸引了不少外贸工厂和传统跨境电商卖家等玩家入局。2022年这一年&#xff0c;不管是直播带货&#xff0c;短视频带货&#xff0c;还是广告投流&#xff0c;数据都有新的变化。据报道&#…

Word 允许西文在单词中间换行,没用/无效 终极办法

有时在写论文中&#xff0c;英文的调整相当麻烦&#xff0c;为了节约版面&#xff0c;会设置允许西文在单词中间换行。但有时不希望这样&#xff0c;特别是在复制网上英文时&#xff0c;会出现单词分断换行情况&#xff0c;如何解决&#xff1a; 1.一般办法。 在Word选择要调整…