以前我们讲过php单态设计模式之单例模式的理解及单例模式(Singleton)的常见应用场景,现在我们在原来的基础上总结一下。
单例模式,就是保持一个对象只存在一个实例,并且为该唯一实例提供一个全局访问点(一般是一个静态的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");
在单例模式中可能遇到一种比较特殊的情况,比如数据库连接对象,对于大型应用来说,很可能需要连接多台数据库,那么不同的数据库公用一个对象可能会产生问题,比如连接的分配、获取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='localhost', $username='root', $password='123456', $dbname='mydb', $port='3306'){ $key = "{$host}:{$port}:{$username}:{$dbname}"; if (emptyempty(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(); } }
问题1:单例类能否拥有子类,因为单例类的构造方法是私有的,因此无法被继承,如果要继承则需要将构造方法改为protected或public,这就违背了单例模式的本意。因此,如果你想给单例类加子类,那就需要回头想想是否错用了模式,或者结构设计上有问题。
问题2:单例滥用,单例模式相对来说比较好理解和实现,因此一旦认识到单例模式的好处,很可能什么类都想写成单例,因此在使用次模式之前一定要考虑上述3种情况,看是否真的有必要使用。
教程网址:
欢迎收藏∩_∩但请保留本文链接。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

SecList
SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기
