浅谈PHP中常用的3种设计模式
作者:老俊说技术 发布时间:2023-10-18 06:23:02
什么是设计模式
设计模式是针对软件开发中出现的常见问题的可重用解决方案。它们并不特定于任何编程语言或框架,而是描述了可应用于各种情况的一般原则和最佳实践。
使用设计模式可以帮助您编写更好的代码
提高代码的可读性和可维护性
降低代码的复杂性和耦合性
提高代码的可重用性和可扩展性
增强代码的可测试性和可靠性
单例模式
单例模式的核心是确保一个类只有一个实例。单例模式是一种设计模式,可确保在整个应用程序中只存在一个类的实例。当您需要控制对共享资源(例如数据库连接、配置文件或记录器)的访问时,这很有用。
单例模式具有三个主要特点:
防止从外部创建类的新实例的私有构造函数
保存类的单个实例的静态属性
返回类的单个实例的公共静态方法
以下是如何在 PHP 中实现单例模式的示例:
<?php
// Define a class with a private constructor
class Database {
// Declare a static property to hold the single instance
private static $instance = null;
// Declare a private constructor to prevent creating new instances
private function __construct() {
// Connect to the database here
}
// Declare a public static method to get the single instance
public static function getInstance() {
// Check if the instance is null
if (self::$instance == null) {
// Create a new instance and assign it to the property
self::$instance = new Database();
}
// Return the instance
return self::$instance;
}
}
// Get the single instance of the Database class
$db = Database::getInstance();
// Use the instance as needed
$db->query("SELECT * FROM users");
从这个示例来看,单例模式可以帮助您避免创建到同一个数据库的多个连接,这可以提高性能并避免错误。它还可以帮助您集中配置和管理共享资源。
但是,单例模式也有一些缺点,比如:
它可以在您的代码中引入全局状态和隐藏的依赖项,这会使测试和调试变得更加困难
它可能违反单一职责原则,因为类必须同时管理自己的逻辑和自己的创建
它会使您的代码不那么灵活,无法适应不断变化的需求,因为您无法轻松替换或扩展单个实例
因此,您应该谨慎使用单例模式,并且只有在真正需要时才使用。您还应该考虑使用依赖注入或服务容器作为替代方案,以通过更好的设计实现类似的结果。
工厂模式
工厂模式是指在不指定类的情况下创建对象工厂模式是一种设计模式,允许您在编译时不知道对象的确切类的情况下创建对象。当您需要根据某些条件(例如用户输入、配置设置或环境变量)创建不同类型的对象时,这很有用。
工厂模式有两个主要组成部分:
定义对象的公共行为的抽象接口或基类
根据条件创建和返回对象的具体工厂类或静态方法
以下是如何在 PHP 中实现工厂模式的示例:
<?php
// Define an abstract interface for shapes
interface Shape {
// Declare an abstract method to draw the shape
public function draw();
}
// Define a concrete class for circles that implements the Shape interface
class Circle implements Shape {
// Declare a property to store the radius
private $radius;
// Declare a constructor to initialize the radius
public function __construct($radius) {
$this->radius = $radius;
}
// Implement the draw method to print the circle
public function draw() {
echo "Drawing a circle with radius " . $this->radius . "\n";
}
}
// Define a concrete class for squares that implements the Shape interface
class Square implements Shape {
// Declare a property to store the side length
private $side;
// Declare a constructor to initialize the side length
public function __construct($side) {
$this->side = $side;
}
// Implement the draw method to print the square
public function draw() {
echo "Drawing a square with side length " . $this->side . "\n";
}
}
// Define a static method to create and return shapes based on a parameter
class ShapeFactory {
// Declare a static method that takes a shape name and an optional size as parameters
public static function createShape($name, $size = 1) {
// Switch on the shape name
switch ($name) {
// If it is circle, return a new Circle object with the size as radius
case "circle":
return new Circle($size);
// If it is square, return a new Square object with the size as side length
case "square":
return new Square($size);
// If it is anything else, throw an exception
default:
throw new Exception("Invalid shape name: " . $name);
}
}
}
// Use the factory method to create and use different shapes
$circle = ShapeFactory::createShape("circle", 2);
$square = ShapeFactory::createShape("square", 3);
$circle->draw();
$square->draw();
工厂模式可以通过以下方式帮助您编写更灵活和可维护的代码:
将对象的创建与其使用分离,这允许您在不影响现有代码的情况下更改或添加新类型的对象
将创建对象的逻辑封装在一处,方便测试调试
从客户端代码中隐藏创建对象的复杂性和细节,使其更简单、更清晰
但是,工厂模式也有一些缺点,比如:
它可以在您的代码中引入更多的类和方法,从而增加其大小和复杂性
它会使您的代码缺乏表现力和直观性,因为您必须使用通用名称和参数而不是特定名称和参数
它可以使您的代码的类型安全性降低,因为您必须依赖字符串或常量来指定对象类型
因此,当您有一套清晰稳定的标准来创建不同类型的对象时,您应该使用工厂模式。您还应该考虑使用抽象工厂或构建器模式作为替代方案,以通过不同的抽象级别实现类似的结果。
观察者模式
观察者模式:通知多个对象状态变化观察者模式是一种设计模式,允许您定义对象之间的一对多关系,这样当一个对象改变其状态时,依赖于它的所有其他对象都会自动得到通知和更新。这在您需要实现发布-订阅机制时很有用,例如时事通讯服务、聊天应用程序或股票市场代码。
观察者模式有两个主要组成部分:
维护观察者或订阅者列表并通知他们任何状态更改的主题或发布者
向主题注册并定义处理通知的方法的观察者或订阅者
以下是如何在 PHP 中实现观察者模式的示例:
<?php
// Define an interface for subjects
interface Subject {
// Declare a method to attach an observer to the subject
public function attach(Observer $observer);
// Declare a method to detach an observer from the subject
public function detach(Observer $observer);
// Declare a method to notify all the observers of a state change
public function notify();
}
// Define an interface for observers
interface Observer {
// Declare a method to update the observer with the new state of the subject
public function update(Subject $subject);
}
// Define a concrete class for newsletters that implements the Subject interface
class Newsletter implements Subject {
// Declare a property to store the list of observers
private $observers = array();
// Declare a property to store the latest news
private $news;
// Implement the attach method to add an observer to the list
public function attach(Observer $observer) {
$this->observers[] = $observer;
}
// Implement the detach method to remove an observer from the list
public function detach(Observer $observer) {
$key = array_search($observer, $this->observers, true);
if ($key !== false) {
unset($this->observers[$key]);
}
}
// Implement the notify method to loop through the list and call the update method on each observer
public function notify() {
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
// Declare a method to set the latest news and notify the observers
public function setNews($news) {
$this->news = $news;
$this->notify();
}
// Declare a method to get the latest news
public function getNews() {
return $this->news;
}
}
// Define a concrete class for email subscribers that implements the Observer interface
class EmailSubscriber implements Observer {
// Declare a property to store the email address
private $email;
// Declare a constructor to initialize the email address
public function __construct($email) {
$this->email = $email;
}
// Implement the update method to print the email address and the latest news from the subject
public function update(Subject $subject) {
echo "Sending email to " . $this->email . " with news: " . $subject->getNews() . "\n";
}
}
// Create a new newsletter object
$newsletter = new Newsletter();
// Create some email subscriber objects and attach them to the newsletter object
$subscriber1 = new EmailSubscriber("alice@example.com");
$subscriber2 = new EmailSubscriber("bob@example.com");
$subscriber3 = new EmailSubscriber("charlie@example.com");
$newsletter->attach($subscriber1);
$newsletter->attach($subscriber2);
$newsletter->attach($subscriber3);
// Set some news and see how the subscribers are notified
$newsletter->setNews("PHP Design Patterns are Awesome!");
$newsletter->setNews("Learn More About PHP Design Patterns Here!");
// Detach one subscriber and set some more news and see how only the remaining subscribers are notified
$newsletter->detach($subscriber2);
$newsletter->setNews("Don't Miss This Amazing Offer on PHP Design Patterns!");
观察者模式可以通过以下方式帮助您编写更加模块化和解耦的代码:
分离主题和观察者的关注点,这允许您在不影响主题的情况下更改或添加新类型的观察者
实施事件驱动架构,使您的代码更具响应性和动态性
支持松耦合和高内聚,让你的代码更容易维护和复用
但是,观察者模式也有一些缺点,比如:
如果您没有正确管理主题和观察者之间的引用,它可能会引入内存泄漏和性能问题
它会使您的代码更难理解和调试,因为您必须跟踪多个对象及其跨不同模块的交互
如果你不处理循环依赖或递归通知,它可能会导致意想不到的副作用或无限循环
因此,当您对事件和通知有清晰一致的定义时,您应该使用观察者模式。您还应该考虑使用支持此模式的内置功能或库,例如 PHP 中的 SplSubject 和 SplObserver。
来源:https://juejin.cn/post/7236914763698143293


猜你喜欢
- Metro风格设计主要特点 1.Windows 8 Metro风格设计,实现网站或系统功能的导航 2.纯Javascript实现 3.支持所
- 在面向对象的编程中,很多语言都支持函数重载,能根据函数传递的不同个数、类型的参数来做不同的操作,JS对它却不支持,需要我们额外做些小动作。在
- 本文实例为大家分享了js实现全选取消效果的具体代码,供大家参考,具体内容如下<!DOCTYPE html><html la
- 说明:本文内容都是从Google上搜索来的,本想上http://www.alexa.com/查官方数据,访问非常慢暂且没查。使用本接口将返回
- step 1:perpar database & datause mastergoCreate database Inventory
- 最近用layer ui上传文件遇到了一个问题,我想在上传文件之前把data-id传入后台,layer文档找了一下也没有找到类似的说明,经过一
- 你完成了你的品牌新的应用程序,一切工作就像一个魅力。用户来使用你的网络。每个人是幸福的。 然后,突然间,一个大爆发的用户杀死你的MySQL服
- 有这么一段代码,可以先看一下有没有什么问题,作用是输入一段json字符串,反序列化成map,然后将另一个inputMap的内容,merge进
- 今天,本文向大家推荐20佳国外的脚本下载网站。1- Hot Scripts2- Code Canyon3- User Scripts4- S
- 任务1、循环输出26个字母对应的ASCII码值x=97#代表的是a的ASCII值for _ in range(1,27): &n
- 一、项目概述本次项目目标是实现对自动生成的带有各种噪声的车牌识别。在噪声干扰情况下,车牌字符分割较困难,此次车牌识别是将车牌7个字符同时训练
- 一 ,做好安装前的清理工作rpm -pa | grep mysql 或者 rpm -qa | grep -i mysqlyum remove
- 前言相信大家应该都有所体会,在目前的软件项目中,都会较多的使用到对文档的操作,用于记录和统计相关业务信息。由于系统自身提供了对文档的相关操作
- Python中的列表是简直可说是有容乃大,虽然看似类似C中的数组,但是Python列表可以接受任意的对象元素,比如,字符串,数字,布尔值,甚
- 最近在学习tensorflow框架,在ubuntu下用到python的一个ide --spyder,以下是常用快捷键Ctrl+1:注释/撤销
- Python 条件语句是通过一条或多条语句的执行结果(True 或者 False)来决定执行的代码块。可以通过下图来简单了解条件语句的执行过
- python爬虫模块selenium简介selenium主要是用来做自动化测试,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问
- Python自定义函数在Python编程中,可以使用已经定义好的函数,也可以自定义函数实现某些特殊的功能。自定义函数的语法在Python中,
- 官方函数DataFrame.locAccess a group of rows and columns by label(s) or a b
- 1.虚拟环境它是一个虚拟化的概念,从电脑独立开辟出来的环境。通俗的来讲,虚拟环境就是借助虚拟机来把一部分内容独立出来,我们把这部分独立出来的