php常用设计模式应用场景及示例

单例模式


  • 含义描述

    应用程序中最多只有该类的一个实例存在

  • 应用场景

    常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。

  • 代码示例

    class Singleton {private static $instance; // 定义一个私有的静态变量保存类的实例private function __construct() {} // 将构造函数设为私有,防止外部直接创建对象public static function getInstance() {if (!self::$instance) { // 如果没有实例化则进行实例化操作self::$instance = new self();}return self::$instance; // 返回已经实例化好的对象}
    }// 调用单例模式获取实例
    $obj1 = Singleton::getInstance();
    $obj2 = Singleton::getInstance();var_dump($obj1 === $obj2); // true,两次获取到的都是同一个实例
    

工厂模式


  • 含义描述

    工厂设计模式常用于根据输入参数的不同或者应用程序配置的不同来创建一种专门用来实例化并返回其对应的类的实例

  • 应用场景

    1.后台数据导出:比如可导出文件类型有excel、csv、xml等,同样都是实现导出功能,但是要实例化的类是不同的,实现逻辑也不相同;

    2.支付系统:根据用户选择的支付方式实例化不同的支付类,比如积分、微信、支付宝等支付

    3.缓存功能:一般有文件缓存、session、cookie等,他们的实例也是不同的。

  • 代码示例

    <?php// 定义接口,定义所有对象的通用方法
    interface ShapeInterface
    {public function draw();
    }// 实现接口的具体类,画一个圆形
    class Circle implements ShapeInterface
    {public function draw(){echo "Drawing a circle.\n";}
    }// 实现接口的具体类,画一个长方形
    class Rectangle implements ShapeInterface
    {public function draw(){echo "Drawing a rectangle.\n";}
    }// 工厂类
    class ShapeFactory
    {// 根据传入的形状类型生成对应的对象public static function createShape($shapeType){if ($shapeType == 'circle') {return new Circle();} elseif ($shapeType == 'rectangle') {return new Rectangle();} else {throw new Exception("Invalid shape type: " . $shapeType);}}
    }// 使用工厂类生成对象并调用方法
    try {$circle = ShapeFactory::createShape('circle');$circle->draw();$rectangle = ShapeFactory::createShape('rectangle');$rectangle->draw();// 尝试创建无效的形状类型$invalidShape = ShapeFactory::createShape('triangle');
    } catch (Exception $e) {echo "Error: " . $e->getMessage();
    }输出结果:
    Drawing a circle.
    Drawing a rectangle.
    Error: Invalid shape type: triangle
    

    在这个示例中,我们定义了一个ShapeInterface接口,它包含了一个draw()方法,用于绘制形状。然后,我们创建了两个实现该接口的具体类Circle和Rectangle,它们分别实现了draw()方法来绘制圆形和矩形。

    接下来,我们创建了一个ShapeFactory工厂类,它包含一个静态方法createShape(),该方法根据传入的形状类型(字符串)生成相应的对象实例。在createShape()方法中,我们根据传入的形状类型使用条件语句创建对应的对象,并返回该对象。如果传入的形状类型无效,我们将抛出一个异常。

    最后,我们使用ShapeFactory类来生成圆形和矩形的对象,并调用它们的draw()方法来绘制形状。同时,我们也尝试创建一个无效的形状类型(三角形),以演示异常处理机制。

策略模式


  • 含义描述

    策略设计模式是一种行为设计模式,它允许你在运行时改变对象的行为。在策略模式中,一个类的行为或其算法可以在运行时更改应用场景

  • 应用场景

    1. 商城促销方式:对秒杀、满减、打折等不同促销方式用不同的算法计算不同的结算价格
    2. 日志系统:根据日志的类型做不同的响应
  • 代码示例

    //我们将以一个简单的日志记录系统为例,其中我们可以选择不同的日志策略来记录信息。//首先,我们定义一个日志策略接口:<?php
    interface LoggingStrategy {public function log(string $message);
    }//然后,我们实现几种不同的日志策略,例如控制台日志、文件日志和数据库日志:<?php
    class ConsoleLog implements LoggingStrategy {public function log(string $message) {echo "Console: " . $message . PHP_EOL;}
    }class FileLog implements LoggingStrategy {private $file;public function __construct(string $file) {$this->file = $file;}public function log(string $message) {file_put_contents($this->file, "File: " . $message . PHP_EOL, FILE_APPEND);}
    }class DatabaseLog implements LoggingStrategy {private $pdo;public function __construct(PDO $pdo) {$this->pdo = $pdo;}public function log(string $message) {$stmt = $this->pdo->prepare("INSERT INTO logs (message) VALUES (?)");$stmt->execute([$message]);}
    }//接下来,我们创建一个Logger类,该类使用策略模式来记录日志:<?php
    class Logger {private $strategy;public function __construct(LoggingStrategy $strategy) {$this->strategy = $strategy;}public function setStrategy(LoggingStrategy $strategy) {$this->strategy = $strategy;}public function log(string $message) {$this->strategy->log($message);}
    }//最后,我们在主程序中使用Logger类:<?php
    // 创建一个PDO实例用于数据库连接(这里仅作示例,实际使用时需要配置数据库连接参数)
    $pdo = new PDO('mysql:host=localhost;dbname=mydb', 'username', 'password');// 创建不同的日志策略实例
    $consoleLog = new ConsoleLog();
    $fileLog = new FileLog('path/to/logfile.log');
    $databaseLog = new DatabaseLog($pdo);// 创建一个Logger实例,并设置初始的日志策略为控制台日志
    $logger = new Logger($consoleLog);
    $logger->log("This is a console log message.");// 更改日志策略为文件日志
    $logger->setStrategy($fileLog);
    $logger->log("This is a file log message.");// 更改日志策略为数据库日志
    $logger->setStrategy($databaseLog);
    $logger->log("This is a database log message.");在这个例子中,Logger类是一个上下文类,它使用LoggingStrategy接口来定义日志记录的行为。通过setStrategy方法,我们可以动态地更改日志记录的策略,从而在不同的场景下使用不同的日志记录方式。这样,如果我们想要添加新的日志策略,只需要实现LoggingStrategy接口,并在Logger中使用它即可,而不需要修改Logger类的代码。
    
    • 与工厂模式的区别
      1. 目的不同:工厂模式的目的是创建对象,根据传入的参数或条件返回不同类型的对象;而策略模式的目的是在运行时选择不同的行为或算法。
      2. 关注点不同:工厂模式关注对象的创建过程,封装了对象的创建逻辑;而策略模式关注行为或算法的选择和切换。
      3. 使用场景不同:工厂模式通常用于处理对象的创建问题,如多数据库选择、类库文件加载等;而策略模式通常用于处理算法或行为的选择问题,如排序算法的选择、支付方式的选择等。

观察者模式


  • 含义描述

    观察者模式是一种软件设计模式,属于对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

  • 应用场景

    1. 事件处理:观察者模式常被用于事件处理机制,如图形用户界面(GUI)框架中的按钮点击事件、窗口的打开和关闭事件等。观察者对象可以订阅这些特定事件,并在事件发生时接收通知并执行相应的操作。
    2. 消息通知:在消息通知系统中,如聊天应用、社交媒体平台等需要实时消息传递的场景中,观察者模式也得到了广泛应用。当发布者发布新消息时,订阅该消息的观察者会收到通知并进行相应的处理。
    3. 股票市场:在股票市场中,观察者模式可以用于实现订阅者监听发布者的状态变化并作出响应。
    4. 日志记录:观察者模式还可以用于实时日志记录系统。在这种情况下,日志记录器充当被观察者,而观察者可以是日志分析器、报警系统等。当日志发生变化时,观察者会收到通知并执行相应的操作,如生成报告、发送警报等。
    5. Redis中的发布订阅:Redis中的基于频道的发布订阅也是观察者模式的一个应用实例。
  • 代码示例

    PHP 中实现观察者模式,可以定义一个 Subject 类和一个 Observer 接口。Subject 类维护一个观察者列表,并提供添加、删除和通知观察者的方法。Observer 接口定义了观察者需要实现的方法。下面是一个简单的示例代码,展示了如何在 PHP 中实现观察者模式:<?php
    // Observer 接口
    interface Observer {public function update(Subject $subject);
    }// ConcreteObserver 类
    class ConcreteObserver implements Observer {private $name;public function __construct($name) {$this->name = $name;}public function update(Subject $subject) {echo "Observer {$this->name} received update: {$subject->getState()}\n";}
    }// Subject 类
    class Subject {private $observers = [];private $state;public function attach(Observer $observer) {$this->observers[] = $observer;}public function detach(Observer $observer) {$key = array_search($observer, $this->observers);if ($key !== false) {unset($this->observers[$key]);}}public function notify() {foreach ($this->observers as $observer) {$observer->update($this);}}public function setState($state) {$this->state = $state;$this->notify();}public function getState() {return $this->state;}
    }// 使用示例
    $subject = new Subject();$observer1 = new ConcreteObserver('Observer 1');
    $observer2 = new ConcreteObserver('Observer 2');$subject->attach($observer1);
    $subject->attach($observer2);$subject->setState('New state');$subject->detach($observer1);$subject->setState('Another state');在上面的示例中,我们定义了一个 Observer 接口,它包含了一个 update 方法,用于接收主题的状态更新。ConcreteObserver 类实现了 Observer 接口,并在 update 方法中打印接收到的更新信息。Subject 类维护了一个观察者列表($observers),并提供了 attach 方法用于添加观察者,detach 方法用于移除观察者,以及 notify 方法用于通知所有观察者。setState 方法用于设置主题的状态,并在状态改变时调用 notify 方法通知观察者。getState 方法用于获取当前的主题状态。在使用示例中,我们创建了一个主题对象 $subject,并将两个观察者对象 $observer1$observer2 添加到主题中。然后,我们通过调用 setState 方法改变主题的状态,并观察者的 update 方法将被调用,打印接收到的更新信息。最后,我们通过调用 detach 方法移除了一个观察者,并再次改变主题的状态,观察者的更新信息将不再打印。
    

装饰器模式


  • 含义描述

    装饰器设计模式是一种结构型设计模式,它允许动态地给一个对象添加一些额外的职责或功能

  • 应用场景

    1. 游戏开发:装备各种不同的武器装备增加各种属性,如攻击力、HP和防御等
    2. 点餐系统:根据用户选择的不同商品规格和配料,计算价格和满减优惠
  • 代码示例

    // 定义一个接口,表示被装饰的对象
    interface Coffee {public function getCost();public function getIngredients();
    }// 创建一个实现了Coffee接口的具体对象,即被装饰的对象
    class SimpleCoffee implements Coffee {public function getCost() {return 1.99;}public function getIngredients() {return "Coffee";}
    }// 创建一个加奶咖啡装饰器类,它包装了Coffee对象
    class CoffeeWithMilk extends SimpleCoffee implements Coffee {private $coffee;public function __construct(Coffee $coffee) {$this->coffee = $coffee;}public function getCost() {return $this->coffee->getCost() + 0.30;}public function getIngredients() {return $this->coffee->getIngredients() . ", Milk";}
    }// 创建一个加糖咖啡的装饰器类,它也为Coffee对象添加额外的行为
    class CoffeeWithSugar extends CoffeeWithMilk {public function getCost() {return parent::getCost() + 0.20;}public function getIngredients() {return parent::getIngredients() . ", Sugar";}
    }// 使用装饰器
    $coffee = new SimpleCoffee();
    echo "Cost: " . $coffee->getCost() . "\n";
    echo "Ingredients: " . $coffee->getIngredients() . "\n";$coffeeWithMilk = new CoffeeWithMilk($coffee);
    echo "Cost: " . $coffeeWithMilk->getCost() . "\n";
    echo "Ingredients: " . $coffeeWithMilk->getIngredients() . "\n";$coffeeWithSugar = new CoffeeWithSugar($coffeeWithMilk);
    echo "Cost: " . $coffeeWithSugar->getCost() . "\n";
    echo "Ingredients: " . $coffeeWithSugar->getIngredients() . "\n";输出结果:
    Cost: 1.99
    Ingredients: Coffee
    Cost: 2.29
    Ingredients: Coffee, Milk
    Cost: 2.79
    Ingredients: Coffee, Milk, Milk, Sugar
    

    在这个示例中,我们有一个Coffee接口和两个实现了该接口的类:SimpleCoffee(被装饰的对象)和CoffeeWithMilk、CoffeeWithSugar(装饰器类)。
    CoffeeWithMilk装饰器类包装了一个Coffee对象,并添加了牛奶和额外的成本。CoffeeWithSugar装饰器类进一步包装了CoffeeWithMilk对象,并添加了糖和额外的成本。
    通过链式使用装饰器,我们可以动态地构建具有不同功能和成本的咖啡。

迭代器模式


  • 含义描述

    迭代器设计模式允许你顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。通过使用迭代器,聚合对象与其迭代逻辑可以分离,从而使代码更加灵活和可扩展

  • 应用场景

    1. 操作链表、树、图:用迭代器模式可以让集合类隐藏这些复杂性,只暴露“next”、“hasNext”等基本迭代操作,这样既简化了外部对集合元素的操作,也保护了集合的封装性
    2. for、foreach循环:通过for语句直接遍历任何实现了迭代协议的对象,极大地简化了遍历过程,并且能够利用生成器模式实现惰性计算和流式处理
  • 代码示例

    //首先,定义一个迭代器接口(Iterator):interface Iterator {public function current();public function key();public function next();public function rewind();public function valid();
    }//然后,定义一个具体的迭代器类(ConcreteIterator),它实现了迭代器接口:class ConcreteIterator implements Iterator {private $data;private $position = 0;public function __construct(array $data) {$this->data = $data;}public function current() {return $this->data[$this->position];}public function key() {return $this->position;}public function next() {$this->position++;}public function rewind() {$this->position = 0;}public function valid() {return isset($this->data[$this->position]);}
    }//接下来,定义一个聚合对象接口(Aggregate),该接口定义了一个方法来创建迭代器:interface Aggregate {public function createIterator();
    }//然后,创建一个实现了聚合对象接口的具体聚合类(ConcreteAggregate):class ConcreteAggregate implements Aggregate {private $data = [];public function add($item) {$this->data[] = $item;}public function createIterator() {return new ConcreteIterator($this->data);}
    }//最后,你可以使用这些类来实现迭代器的功能:// 创建一个聚合对象
    $aggregate = new ConcreteAggregate();
    $aggregate->add('Element 1');
    $aggregate->add('Element 2');
    $aggregate->add('Element 3');// 获取聚合对象的迭代器
    $iterator = $aggregate->createIterator();// 使用迭代器遍历聚合对象中的元素
    $iterator->rewind();
    while ($iterator->valid()) {echo $iterator->current() . "\n";$iterator->next();
    }
    

    在上面的示例中,ConcreteAggregate 类存储了一个元素数组,并提供了 createIterator() 方法来创建一个新的 ConcreteIterator 实例。ConcreteIterator 类实现了 Iterator 接口,用于遍历 ConcreteAggregate 中的元素。

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

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

相关文章

【恒源智享云】conda虚拟环境的操作指令

conda虚拟环境的操作指令 由于虚拟环境经常会用到&#xff0c;但是我总忘记&#xff0c;所以写个博客&#xff0c;留作自用。 在恒源智享云上&#xff0c;可以直接在终端界面输入指令&#xff0c;例如&#xff1a; 查看已经存在的虚拟环境列表 conda env list查看当前虚拟…

C语言 编译和链接

1. 翻译环境和运⾏环境 在ANSI?C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指令。 第2种是执⾏环境&#xff0c;它⽤于实际执⾏代码。 我们来看一下过程&#xff1a; 2. 翻译环境 那翻译环境是…

Android系统键值列表

转载于网络&#xff0c;记录下来自用 电话键 键名 描述 键值 KEYCODE_CALL 拨号键5 KEYCODE_ENDCALL 挂机键6 KEYCODE_HOME 按键Home3 KEYCODE_MENU 菜单键82 KEYCODE_BACK 返回键4 KEYCODE_SEARCH 搜索键84 KEYCODE_CAMERA 拍照键27 KEYCODE_FOCUS 拍照对焦键80 KEYCODE_POWE…

《幻兽帕鲁》新手入门 幻兽帕鲁新手开荒攻略 幻兽帕鲁配置要求

2024年1月&#xff0c;讨论热度最高的新游无疑是Pocketpair出品的《幻兽帕鲁》。这部作品发售两周即在Steam游戏平台售出超过1200万份&#xff0c;且Xbox/XGP玩家规模超过700万。不仅如此&#xff0c;该游戏同时在线玩家人数超过200万&#xff0c;在Steam的游戏史上仅次于《绝地…

java中几种对象存储(文件存储)中间件的介绍

一、前言 在博主得到系统中使用的对象存储主要有OSS&#xff08;阿里云的对象存储&#xff09; COS&#xff08;腾讯云的对象存储&#xff09;OBS&#xff08;华为云的对象存储&#xff09;还有就是MinIO 这些玩意。其实这种东西大差不差&#xff0c;几乎实现方式都是一样&…

深入理解Java中的ConcurrentSkipListMap:高效并发的有序映射

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 摘要&#xff1a;本文将详细介绍Java中的ConcurrentSkipListMap&#xff0c;一个支持高效并发操作的有序映射。我们将深入探讨其数…

xilinx SDK 2018.3 undefined reference to `f_mount‘,`f_open‘等等

用xilinx SDK 写SD的读写实验时&#xff0c;已经添加了头文件ff.h并且没有报错&#xff0c;但是当用到内部的函数f_mount&#xff0c;f_open’等等时却显示未定义。 很可能是漏掉了在ZYNQ中定义SD的MIO接口&#xff0c;在下方图示中进行定义&#xff08;需要查找自己板子的原理…

Java零基础入门到精通_Day 1

01 Java 语言发展史 Java语言是美国Sun公司(StanfordUniversity Network)在1995年推出的 计算机语言Java之父:詹姆斯高斯林(ames Gosling) 重要的版本过度&#xff1a; 2004年 Java 5.0 2014年 Java 8.0 2018年 9月 Java 11.0 &#xff08;目前所使用的&#xff09; 02 J…

函数的说明文档

函数是纯代码语言&#xff0c;想要理解其含义&#xff0c;就需要一行行去阅读理解代码&#xff0c;效率比较低。 我们可以给函数添加说明文档&#xff0c;辅助理解函数的作用。 语法如下&#xff1a; 通过多行注释的形式&#xff0c;对函数进行说明解释 内容应写在函数体之前…

leetcode 25、k个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

SPEL表达式及注入漏洞

SPEL,全称为Spring表达式语言&#xff0c;是一个由 Spring 框架提供的表达式语言。它是一种基于字符串的表达式语言&#xff0c;可以在运行时对对象进行查询和操作。 SpEL 支持在XML和注解配置中使用&#xff0c;它可以在Spring框架的各种组件中使用&#xff0c;如Spring MVC …

JavaScript截取字符串的几种方法

1.split() split()用于把一个字符串分割成字符串数组 stringObject.split(separator,howmany) 参数说明&#xff1a; separator参数&#xff1a;必需填。字符串或正则表达式&#xff0c;从该参数指定的地方分割 stringObject。 howmany参数&#xff1a;可选。该参数可指定返…

android 快速实现 recyclerview 的所有item 都执行动画

1.在adapter 里面重写onViewAttachedToWindow 和 onViewDetachedFromWindow 两个方法 package com.example.widget;import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animat…

L3自动驾驶的“双保险”:冗余EPS关键技术解析

摘要: 本文主要介绍冗余EPS的发展路径和关键技术。 引言 在乘用车领域,电动助力转向系统(Electric Power Steering,EPS)相比传统的液压助力转向系统(Hydraulic Power Steering,HPS)具有结构简单、响应迅速、能耗低等优点,因此应用很广。随着智能驾驶的发展,作为底层…

springboot261高校专业实习管理系统的设计和开发

基于spring boot的高校专业实习管理系统的设计与实现 摘 要 随着国内市场经济这几十年来的蓬勃发展&#xff0c;突然遇到了从国外传入国内的互联网技术&#xff0c;互联网产业从开始的群众不信任&#xff0c;到现在的离不开&#xff0c;中间经历了很多挫折。本次开发的高校专…

制造行业大数据应用:四大领域驱动产业升级与智慧发展

一、大数据应用&#xff1a;制造行业的智慧引擎 随着大数据技术的不断突破与普及&#xff0c;制造行业正迎来一场前所未有的变革。大数据应用&#xff0c;如同智慧引擎一般&#xff0c;为制造行业注入了新的活力&#xff0c;推动了产业升级与创新发展。 二、大数据应用在制造行…

外贸人要加油努力,到底怎么做

我们说要加油&#xff0c;要努力&#xff0c;那做外贸我们的力气到底应该往哪里使&#xff1f;想要把外贸做好容易吗&#xff1f; 其实没有一件事情背后他是真正容易的&#xff0c;如果发现自己迷茫了&#xff0c;很有可能是你既要又要&#xff0c;没有自己的一个满足感&#…

鸿蒙ArkTS语言快速入门-TS(二)

相关文章快速入口&#xff1a;鸿蒙ArkTS语言快速入门-TS&#xff08;三&#xff09; ArkTS入门第二篇 TS入门学习变量声明条件语句if语句switch…case 语句 接口普通函数接口函数类型接口类类型接口继承接口接口继承类 TS入门学习 变量声明 使用let和const声明&#xff0c;替…

Elasticsearch:机器学习与人工智能 - 理解差异

作者&#xff1a;来自 Elastic Aditya Tripathi, Jessica Taylor 长期以来&#xff0c;人工智能几乎完全是科幻小说作家的玩物&#xff0c;人类将技术推得太远&#xff0c;以至于它变得活跃起来 —— 正如好莱坞让我们相信的那样 —— 开始造成严重破坏。 令人愉快的东西&#…

C++中的RAII原则和资源管理如何提高程序效率和安全性?

文章目录 C中的RAII&#xff08;Resource Acquisition Is Initialization&#xff09;原则是一种编程范式&#xff0c;它确保资源在其生命周期内的有效管理。RAII的核心思想是在对象创建时&#xff08;初始化阶段&#xff09;获取资源&#xff0c;并在对象销毁时&#xff08;析…