悠悠楠杉
PHP设计模式实战:单例与工厂模式的深度解析
一、为什么需要设计模式?
在大型PHP项目开发中,我们经常会遇到对象重复创建、资源浪费或依赖关系复杂等问题。设计模式就像建筑师的蓝图,为这些常见问题提供了经过验证的解决方案。今天我们将重点剖析两种最常用的创建型模式:确保全局唯一访问的单例模式,以及封装对象创建逻辑的工厂模式。
二、单例模式:严格控制实例数量
2.1 核心思想
单例模式(Singleton)确保一个类只有一个实例,并提供一个全局访问点。这在数据库连接、日志记录器等场景尤为关键。
php
class DatabaseConnection {
private static $instance = null;
private $connection;
// 私有化构造函数
private function __construct() {
$this->connection = new PDO("mysql:host=localhost;dbname=test", "user", "pass");
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 防止克隆
private function __clone() {}
// 防止反序列化
private function __wakeup() {}
}
2.2 实现要点
- 私有构造函数:禁止通过
new
创建实例 - 静态存储属性:保存唯一实例
- 全局访问方法:通过
getInstance()
获取 - 防克隆保护:避免通过克隆创建新实例
实际项目中,建议结合依赖注入容器使用,避免过度依赖全局状态。
三、工厂模式:智能的对象创建者
3.1 模式价值
工厂模式(Factory)将对象创建逻辑与使用代码分离,特别适用于:
- 创建过程复杂的对象
- 需要根据不同条件创建不同实例
- 希望隐藏具体实现类
3.2 简单工厂实现
php
interface Logger {
public function log($message);
}
class FileLogger implements Logger {
public function log($message) {
fileputcontents('app.log', $message, FILE_APPEND);
}
}
class DatabaseLogger implements Logger {
public function log($message) {
// 数据库记录实现
}
}
class LoggerFactory {
public static function createLogger($type): Logger {
return match($type) {
'file' => new FileLogger(),
'db' => new DatabaseLogger(),
default => throw new InvalidArgumentException("未知的日志类型")
};
}
}
// 使用示例
$logger = LoggerFactory::createLogger('file');
$logger->log('系统启动');
3.3 工厂方法模式进阶
当对象创建逻辑更复杂时,可以采用工厂方法:php
abstract class ApptEncoder {
abstract public function encode(): string;
}
class BloggsApptEncoder extends ApptEncoder {
public function encode(): string {
return "数据格式化为Bloggs格式\n";
}
}
abstract class CommsManager {
abstract public function getApptEncoder(): ApptEncoder;
}
class BloggsCommsManager extends CommsManager {
public function getApptEncoder(): ApptEncoder {
return new BloggsApptEncoder();
}
}
四、模式组合实战
在实际开发中,我们经常组合使用这些模式。例如数据库连接池:
php
class DBConnectionPool {
private static $instances = [];
private const MAXPOOLSIZE = 5;
public static function getConnection($config): PDO {
$key = md5(serialize($config));
if (!isset(self::$instances[$key]) || count(self::$instances) < self::MAX_POOL_SIZE) {
self::$instances[$key] = new PDO(
$config['dsn'],
$config['user'],
$config['password']
);
}
return self::$instances[$key];
}
}
五、模式选择指南
| 模式 | 适用场景 | 优势 |
|-------------|---------------------------------|-------------------------|
| 单例 | 需要全局唯一访问的资源 | 减少资源消耗 |
| 简单工厂| 创建逻辑简单的多态对象 | 客户端与实现解耦 |
| 工厂方法| 需要扩展的复杂对象家族 | 支持开闭原则 |
注意事项:
1. 单例模式可能带来测试困难
2. 过度使用工厂会导致类爆炸
3. 现代框架通常内置这些模式的实现
掌握这些模式后,你会发现自己写的PHP代码更加优雅、可维护。记住:模式是工具而非教条,根据实际场景灵活运用才是关键。