目录
问题
单例作为反模式
结论
首页 后端开发 php教程 单例模式:专为提高效率而设计

单例模式:专为提高效率而设计

Aug 31, 2023 pm 01:53 PM

单例模式:专为提高效率而设计

在本文中,您将了解如何实现单例设计模式,以及为什么以及何时在应用程序中使用此模式。正如“Singleton”这个名字所暗示的那样,这种方法允许我们创建一个类的唯一一个对象。

让我们看看维基百科上有关于此设计模式的内容:

单例模式是一种将类的实例化限制为一个对象的设计模式。当只需要一个对象来协调整个系统的操作时,这非常有用。

正如上面定义中提到的,当我们想要确保任何类都需要创建一个且仅有一个对象时,那么我们应该为该类实现 Singleton 模式。

p>

你可能会问为什么我们应该实现这样一个类,它允许我们只创建它的一个对象。我想说,我们可以在很多用例中应用这种设计模式。其中包括:配置类、会话类、数据库类等等。

本文中我将以数据库类为例。首先,我们将看看如果没有为这样的类实现单例模式,会出现什么问题。

问题

想象一个非常简单的数据库连接类,一旦我们创建该类的对象,它就会创建与数据库的连接。

class database {
    
	private $dbName = null, $dbHost = null, $dbPass = null, $dbUser = null;
	
	public function __construct($dbDetails = array()) {
		
		$this->dbName = $dbDetails['db_name'];
		$this->dbHost = $dbDetails['db_host'];
		$this->dbUser = $dbDetails['db_user'];
		$this->dbPass = $dbDetails['db_pass'];

		$this->dbh = new PDO('mysql:host='.$this->dbHost.';dbname='.$this->dbName, $this->dbUser, $this->dbPass);
		
	}
	
}
登录后复制

在上面的代码示例中,您可以看到,每次创建此类的对象时,它都会与数据库建立连接。因此,如果开发人员在多个位置创建了此类的对象,想象一下它将与数据库服务器创建的(相同)数据库连接的数量。

因此,开发人员在不知不觉中犯了错误,从而对数据库和应用服务器的速度产生了巨大影响。让我们通过创建该类的不同对象来看看同样的事情。

$dbDetails = array(
    	'db_name' => 'designpatterns',
		'db_host' => 'localhost',
		'db_user' => 'root',
		'db_pass' => 'mysqldba'
);

$db1 = new database($dbDetails);
var_dump($db1);
$db2 = new database($dbDetails);
var_dump($db2);
$db3 = new database($dbDetails);
var_dump($db3);
$db4 = new database($dbDetails);
var_dump($db4);

// Output
object(database)[1]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[2]
object(database)[3]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[4]
object(database)[5]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[6]
object(database)[7]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[8]
登录后复制

如果你看到上面代码的输出和输出,你可以看到每个对象都分配了一个新的资源ID,所以所有对象都是全新的引用,因此它也分配单独的内存。这样不知不觉中我们的应用程序就会占用实际上不需要的资源。

解决方案

开发人员如何使用我们的基础框架不在我们的控制范围内。代码审查过程发生后,它就在我们的控制之下,但在开发过程中,我们不能一直站在他们身后。

为了克服这种情况,我们应该使我们的基类不能创建一个类的多个对象;相反,它会给出一个已经创建的对象(如果有)。在这种情况下,我们应该考虑为我们的基类开发单例模式。

在实现这一模式时,我们的目标是允许一次且仅创建一个类的对象。请允许我添加下面的类代码,然后我们将详细介绍该类的每个部分。

class database {
    
	private $dbName = null, $dbHost = null, $dbPass = null, $dbUser = null;
	private static $instance = null;
	
	private function __construct($dbDetails = array()) {
		
		// Please note that this is Private Constructor
		
		$this->dbName = $dbDetails['db_name'];
		$this->dbHost = $dbDetails['db_host'];
		$this->dbUser = $dbDetails['db_user'];
		$this->dbPass = $dbDetails['db_pass'];

		// Your Code here to connect to database //
		$this->dbh = new PDO('mysql:host='.$this->dbHost.';dbname='.$this->dbName, $this->dbUser, $this->dbPass);
	}
	
	public static function connect($dbDetails = array()) {
		
		// Check if instance is already exists 		
		if(self::$instance == null) {
			self::$instance = new database($dbDetails);
		}
		
		return self::$instance;
		
	}
	
	private function __clone() {
		// Stopping Clonning of Object
	}
	
	private function __wakeup() {
		// Stopping unserialize of object
	}
	
}
登录后复制

几乎没有迹象表明上面的类是 Singleton 类。首先是私有构造函数,它防止使用 new 关键字创建对象。另一种指示是一个静态成员变量,它保存对已创建对象的引用。

$dbDetails = array(
    	'db_name' => 'designpatterns',
		'db_host' => 'localhost',
		'db_user' => 'root',
		'db_pass' => 'mysqldba'
);

$db1 = database::connect($dbDetails);
var_dump($db1);
$db2 = database::connect($dbDetails);
var_dump($db2);
$db3 = database::connect($dbDetails);
var_dump($db3);
$db4 = database::connect($dbDetails);
var_dump($db4);

// Output

object(database)[1]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[2]
object(database)[1]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[2]
object(database)[1]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[2]
object(database)[1]
  private 'dbName' => string 'designpatterns' (length=14)
  private 'dbHost' => string 'localhost' (length=9)
  private 'dbPass' => string 'mysqldba' (length=8)
  private 'dbUser' => string 'root' (length=4)
  public 'dbh' => object(PDO)[2]
登录后复制

如果比较两个部分的输出,那么您将看到,在单例模式的输出中,所有不同对象的对象资源 ID 都是相同的。但不使用设计模式时情况并非如此。

单例作为反模式

由于各种原因,这种设计模式也称为反模式,我将在下面提到:

  1. 由于其控制自身创建和生命周期的质量,它违反了单一职责原则。
  2. 它将全局状态引入您的应用程序。我想说全局状态非常糟糕,因为任何代码都可以改变它的值。所以在调试的时候很难发现哪部分代码做了当前阶段的全局变量。

  3. 如果您正在进行单元测试,那么单例通常是一个坏主意,并且不执行单元测试通常也是一个坏主意。

结论

我尽力解释了互联网上广泛讨论的单例设计模式。我希望这篇文章对您有所帮助。我们已经介绍了该模式的两个方面,即设计模式和反模式。

请在下面发表您的意见、建议和/或问题,我会尽快回复。您还可以通过 Twitter @XpertDevelopers 联系我或直接给我发电子邮件。

以上是单例模式:专为提高效率而设计的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在Laravel中使用Flash会话数据 在Laravel中使用Flash会话数据 Mar 12, 2025 pm 05:08 PM

Laravel使用其直观的闪存方法简化了处理临时会话数据。这非常适合在您的应用程序中显示简短的消息,警报或通知。 默认情况下,数据仅针对后续请求: $请求 -

php中的卷曲:如何在REST API中使用PHP卷曲扩展 php中的卷曲:如何在REST API中使用PHP卷曲扩展 Mar 14, 2025 am 11:42 AM

PHP客户端URL(curl)扩展是开发人员的强大工具,可以与远程服务器和REST API无缝交互。通过利用Libcurl(备受尊敬的多协议文件传输库),PHP curl促进了有效的执行

简化的HTTP响应在Laravel测试中模拟了 简化的HTTP响应在Laravel测试中模拟了 Mar 12, 2025 pm 05:09 PM

Laravel 提供简洁的 HTTP 响应模拟语法,简化了 HTTP 交互测试。这种方法显着减少了代码冗余,同时使您的测试模拟更直观。 基本实现提供了多种响应类型快捷方式: use Illuminate\Support\Facades\Http; Http::fake([ 'google.com' => 'Hello World', 'github.com' => ['foo' => 'bar'], 'forge.laravel.com' =>

在Codecanyon上的12个最佳PHP聊天脚本 在Codecanyon上的12个最佳PHP聊天脚本 Mar 13, 2025 pm 12:08 PM

您是否想为客户最紧迫的问题提供实时的即时解决方案? 实时聊天使您可以与客户进行实时对话,并立即解决他们的问题。它允许您为您的自定义提供更快的服务

解释PHP中晚期静态结合的概念。 解释PHP中晚期静态结合的概念。 Mar 21, 2025 pm 01:33 PM

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

框架安全功能:防止漏洞。 框架安全功能:防止漏洞。 Mar 28, 2025 pm 05:11 PM

文章讨论了框架中的基本安全功能,以防止漏洞,包括输入验证,身份验证和常规更新。

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

See all articles