Heim php教程 php手册 浅析php单态设计模式之单例模式的理解

浅析php单态设计模式之单例模式的理解

May 26, 2016 am 08:20 AM
select

单态模式的主要作用是保证在面向对象编程设计中,一个类只能有一个实例对象存在。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。

1.单态设计模式含义:

单态模式的主要作用是保证在面向对象编程设计中,一个类只能有一个实例对象存在。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。

2.单台模式的三个关键点:

① 需要一个保存类的唯一实例的静态成员变量;

②构造函数和克隆函数必须声明为私有的,防止外部程序new类从而失去单例模式的意义;

③必须提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一实例的一个引用 。

<?php
class DB {
    private static $obj = null; //声明一个私有的,静态的成员属性$obj
    private function__construct() { //私有构造方法,只能在类的内部实例化对象
        echo "连接数据库成功<br>";
    }
    public static function getInstance() { // 通过此静态方法才能获取本类的对象
        if (is_null(self::$obj)) //如果本类中的$obj为空,说明还没有被实例化过
        self::$obj = new self(); //实例化本类对象
        return self::$obj; //返回本类的对象
    }
    public function query($sql) { //执行SQL语句完成对数据库的操作
        echo $sql;
    }
}
$db = DB::getInstance(); //只能使用静态方法getInstance()去获取DB类的对象
$db->query("select *from user"); //访问对象中的成员
?>
Nach dem Login kopieren

单例模式,就是保持一个对象只存在一个实例。并且为该唯一实例提供一个全局访问点(一般是一个静态的getInstance方法)。单例模式应用场景非常广泛,例如:

数据库操作对象

日志写入对象

全局配置解析对象等

这些场景的共同特征是从业务逻辑上来看运行期间改对象却是

只需要一个实例

不断new多个实例会增加不必要的资源消耗

全局调用便利

下面分别说明这三个方面:

1. 业务上只需要一个实例

以数据库连接对象为例,加入有一个购物网站,有一个MySQL数据库

127.0.0.1:3306

,那么在一个进程中无论我们需要进行多少次针对改数据库的操作,都只需要连接数据库一次,使用相同的数据库连接句柄(MySQL Connection Resource),从业务需求上来看就只需要一个实例。

相反,同样以购物网站为例,存在许多商品,这些商品都不一样(id,name,price..),这个时候需要显示一个商品列表,加入我们建立一个

Product

作为数据映射对象,那么从业务需求上来说,一个实例就无法满足业务需求,因为每个商品都不一样。

2. 不断new操作增加不必要的资源消耗

我们一般会在类的构造方法(new操作肯定会调用)中进行一些业务操作,例如数据库连接对象可能会在构造方法中尝试读取数据库配置并进行数据库连接(如mysqli::__construct())、日志写入对象会判断日志写入目录是否存在并写入(不存在可能尝试创建改目录)、全局配置解析对象可能需要定位配置文件的保存目录并进行文件扫描等。

这些业务都会消耗相当的资源,如果在一个进程中我们值需要做一次,将会非常有利于我们提高应用的运行效率。

3. 全局调用便利

因为单例模式的一大特点就是通过静态方法获取对象实例,那么就意味着访问对象的方法时不需要先new一个对象的实例,如果改对象需要很多地方使用,则提高了调用的便利性。

通过一个日志操作类来举例:

class Logger{
    //首先,需要一个私有的静态变量来存储产生的对象实例
    private static $instance;
    //业务变量,保存日志写入路径
    private $logDir;
    //构造方法,注意必须也是私有的,不允许被外部实例化(即在外部被new)
    private function __construct(){
        //调试输出,测试对象被new的次数
        echo "new Logger instance rn";
        $logDir = sys_get_temp_dir(). DIRECTORY_SEPARATOR . "logs";
        if(!is_dir($logDir) || !file_exists($logDir)){
            @mkdir($logDir);
        }
        $this->logDir = $logDir;
    }
    //类唯一实例的全局访问点,用于判断并返回对象实例,供外部调用
    public static function getInstance(){
        if(is_null(self::$instance)){
            $class = __CLASS__; //获取本对象的类型,也可以用new self()方式
            self::$instance = new $class();
        }
        return self::$instance;
    }
    //重载__clone()方法,不允许对象对克隆
    public function __clone(){
        throw new Exception("Singleton Class Can Not Be Cloned");
    }
    //具体的业务方法,实际可以有很多方法
    public function logError($message){
        $logFile = $this->logDir . DIRECTORY_SEPARATOR . "error.log";
        error_log($message, 3, $logFile);
    }
}
//日志调用
$logger = Logger::getInstance();
$logger->logError("An error occured");
$logger->logError("Another error occured");
//或者这样调用
Logger::getInstance()->logError("Still have error");
Logger::getInstance()->logError("I should fix it");
Nach dem Login kopieren

在单例模式中可能遇到一种比较特殊的情况,比如数据库连接对象,对于大型应用来说,很可能需要连接多台数据库,那么不同的数据库公用一个对象可能会产生问题,比如连接的分配、获取

insert_id

last_error

等。这个问题也比较好解决,就是把我们的$instance变量变成一个关联数组,通过给getInstance方法传入不同的参数获取不同的"单例对象"(引号的含义是:严格来说类可能被new多次,但是这个new也是在我们的控制之内的,而不是在类外部):

class MysqlServer{
    //注意,变成复数了哦^_^  当然只是为了标识而已
    private static $instances = array();
    //业务变量,保持当前实例的mysqli对象
    private $conn;
    //显著特征:私有的构造方法,避免在类外部被实例化
    private function __construct($host, $username, $password, $dbname, $port){
        $this->conn = new mysqli($host, $username, $password, $dbname, $port);
    }
    //类唯一实例的全局访问点
    public static function getInstance($host=&#39;localhost&#39;, $username=&#39;root&#39;, $password=&#39;123456&#39;, $dbname=&#39;mydb&#39;, $port=&#39;3306&#39;){
        $key = "{$host}:{$port}:{$username}:{$dbname}";
        if (empty(self::$instances[$key])){
            //这里也可以用 new self(); 的方式
            $class = __CLASS__;
            self::$instances[$key] = new $class($host, $username, $password, $dbname, $port);
        }
        return self::$instances[$key];
    }
    //重载__clone方法,不允许对象实例被克隆
    public function __clone(){
        throw new Exception("Singleton Class Can Not Be Cloned");
    }
    //查询业务方法,后面省略其它业务方法
    public function query($sql){
        return $this->conn->query($sql);
    }
    //尽早释放资源
    public function __destruct(){
        $this->conn->close();
    }
}
Nach dem Login kopieren

问题1:单例类能否拥有子类,因为单例类的构造方法是私有的,因此无法被继承,如果要继承则需要将构造方法改为protected或public,这就违背了单例模式的本意。因此,如果你想给单例类加子类,那就需要回头想想是否错用了模式,或者结构设计上有问题。

问题2:单例滥用,单例模式相对来说比较好理解和实现,因此一旦认识到单例模式的好处,很可能什么类都想写成单例,因此在使用次模式之前一定要考虑上述3种情况,看是否真的有必要使用。


永久地址:

转载随意~请带上教程地址吧^^

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

So verbergen Sie das ausgewählte Element in jquery So verbergen Sie das ausgewählte Element in jquery Aug 15, 2023 pm 01:56 PM

So verbergen Sie das Select-Element in JQuery: 1. Methode hide (), fügen Sie die jQuery-Bibliothek in die HTML-Seite ein, Sie können verschiedene Selektoren verwenden, um das Select-Element auszublenden, der ID-Selektor ersetzt die SelectId durch die ID des von Ihnen ausgewählten Elements tatsächlich verwenden; 2. css()-Methode, verwenden Sie den ID-Selektor, um das ausgewählte Element auszuwählen, das ausgeblendet werden muss, verwenden Sie die css()-Methode, um das Anzeigeattribut auf „none“ zu setzen, und ersetzen Sie selectId durch die ID des ausgewählten Elements.

Asynchrone Verarbeitungsmethode von Select Channels Go zur gleichzeitigen Programmierung mit Golang Asynchrone Verarbeitungsmethode von Select Channels Go zur gleichzeitigen Programmierung mit Golang Sep 28, 2023 pm 05:27 PM

Asynchrone Verarbeitungsmethode der gleichzeitigen Programmierung von SelectChannelsGo mit Golang Einführung: Die gleichzeitige Programmierung ist ein wichtiger Bereich in der modernen Softwareentwicklung, der die Leistung und Reaktionsfähigkeit von Anwendungen effektiv verbessern kann. In der Go-Sprache kann die gleichzeitige Programmierung mithilfe von Channels- und Select-Anweisungen einfach und effizient implementiert werden. In diesem Artikel wird die Verwendung von Golang für die asynchrone Verarbeitungsmethode der gleichzeitigen Programmierung von SelectChannelsGo vorgestellt und spezifische Informationen bereitgestellt

So implementieren Sie die Änderungsereignisbindung ausgewählter Elemente in jQuery So implementieren Sie die Änderungsereignisbindung ausgewählter Elemente in jQuery Feb 23, 2024 pm 01:12 PM

jQuery ist eine beliebte JavaScript-Bibliothek, die zur Vereinfachung der DOM-Manipulation, Ereignisbehandlung, Animationseffekte usw. verwendet werden kann. Bei der Webentwicklung stoßen wir häufig auf Situationen, in denen wir die Ereignisbindung für ausgewählte Elemente ändern müssen. In diesem Artikel wird erläutert, wie Sie mit jQuery ausgewählte Elementänderungsereignisse binden, und es werden spezifische Codebeispiele bereitgestellt. Zuerst müssen wir ein Dropdown-Menü mit Optionen erstellen, die Beschriftungen verwenden:

Was ist der Grund, warum Linux select verwendet? Was ist der Grund, warum Linux select verwendet? May 19, 2023 pm 03:07 PM

Da Select es Entwicklern ermöglicht, gleichzeitig auf mehrere Dateipuffer zu warten, kann dies die E/A-Wartezeit verkürzen und die E/A-Effizienz des Prozesses verbessern. Die Funktion select() ist eine E/A-Multiplexfunktion, die es dem Programm ermöglicht, mehrere Dateideskriptoren zu überwachen und darauf zu warten, dass einer oder mehrere der überwachten Dateideskriptoren „bereit“ werden. Bezieht sich auf: die Datei Der Deskriptor ist nicht mehr blockiert und kann für bestimmte Arten von E/A-Vorgängen verwendet werden, einschließlich lesbarer, beschreibbarer und Ausnahmen. select ist eine Computerfunktion, die sich in der Header-Datei #include befindet. Diese Funktion wird verwendet, um Dateideskriptoränderungen zu überwachen – Lesen, Schreiben oder Ausnahmen. 1. Einführung in die Auswahlfunktion Die Auswahlfunktion ist eine E/A-Multiplexfunktion.

So verwenden Sie die Select-Syntax von MySQL So verwenden Sie die Select-Syntax von MySQL Jun 01, 2023 pm 07:37 PM

1. Bei Schlüsselwörtern in SQL-Anweisungen wird die Groß-/Kleinschreibung nicht beachtet. SELECT entspricht SELECT und FROM entspricht from. 2. Um alle Spalten aus der Benutzertabelle auszuwählen, können Sie den Spaltennamen durch das Symbol * ersetzen. Syntax – Dies ist ein Kommentar – Abfrage [alle] Daten aus der durch FEOM angegebenen [Tabelle] * bedeutet [alle Spalten] SELECT*FROM – Abfrage der angegebenen [Tabelle] aus FROM Daten des Spaltennamens (Feld) SELECT Spaltenname FROM Tabellennamensinstanz – Hinweis: Verwenden Sie englische Kommas, um mehrere Spalten zu trennen. Wählen Sie Benutzername und Passwort aus

Implementieren Sie Select Channels Go zur Optimierung der gleichzeitigen Programmierleistung durch Golang Implementieren Sie Select Channels Go zur Optimierung der gleichzeitigen Programmierleistung durch Golang Sep 27, 2023 pm 01:09 PM

Implementieren von SelectChannels durch Golang Leistungsoptimierung der gleichzeitigen Go-Programmierung In der Go-Sprache ist es sehr üblich, Goroutine und Channel zum Implementieren der gleichzeitigen Programmierung zu verwenden. Wenn wir mit mehreren Kanälen arbeiten, verwenden wir normalerweise Select-Anweisungen zum Multiplexen. Bei großer Parallelität kann die Verwendung von Select-Anweisungen jedoch zu Leistungseinbußen führen. In diesem Artikel stellen wir einige Implementierungen von select über Golang vor

Wählen Sie Channels Go-Parallelprogrammierung für Zuverlässigkeit und Robustheit mit Golang aus Wählen Sie Channels Go-Parallelprogrammierung für Zuverlässigkeit und Robustheit mit Golang aus Sep 28, 2023 pm 05:37 PM

SelectChannels für Zuverlässigkeit und Robustheit mithilfe von Golang Einführung in die gleichzeitige Programmierung: In der modernen Softwareentwicklung ist Parallelität zu einem sehr wichtigen Thema geworden. Durch die Verwendung gleichzeitiger Programmierung können Programme schneller reagieren, Rechenressourcen effizienter nutzen und große parallele Rechenaufgaben besser bewältigen. Golang ist eine sehr leistungsfähige gleichzeitige Programmiersprache. Sie bietet eine einfache und effektive Möglichkeit, gleichzeitige Programmierung durch Go-Coroutinen und Kanalmechanismen zu implementieren.

Wenden Sie Select Channels Go-Parallelprogrammierung in Golang-Projekten an, um eine hohe Leistung zu erzielen Wenden Sie Select Channels Go-Parallelprogrammierung in Golang-Projekten an, um eine hohe Leistung zu erzielen Sep 28, 2023 pm 03:58 PM

Anwenden der gleichzeitigen Programmierung von SelectChannelsGo in Golang-Projekten, um eine hohe Leistung zu erzielen. Einführung: Im heutigen Internetzeitalter sind Hochleistungsanwendungen eines der Ziele, die wir verfolgen. Während des Entwicklungsprozesses ist die Verwendung gleichzeitiger Programmierung eines der häufigsten Mittel zur Verbesserung der Anwendungsleistung. In Golang kann eine leistungsstarke gleichzeitige Programmierung mithilfe ausgewählter Anweisungen und Kanäle erreicht werden. In diesem Artikel wird erläutert, wie Sie ausgewählte Anweisungen und Kanäle in Golang-Projekten anwenden

See all articles