设计模式精解:单例、工厂、策略模式实战
设计模式是面向对象设计中反复出现的问题的通用解决方案。掌握设计模式不仅能帮助你写出更灵活、更可维护的代码,还能让你在与团队成员讨论架构时使用共同的语言。本文将深入讲解三种最常用的设计模式——单例模式、工厂模式和策略模式,并通过PHP和JavaScript的实战代码展示它们的应用场景。
一、单例模式
单例模式确保一个类只有一个实例,并提供全局访问点。在需要全局状态管理的场景中非常有用。
经典应用场景:数据库连接、配置管理、日志记录器、缓存管理器
// PHP - 数据库连接单例
class Database
{
private static ?Database $instance = null;
private PDO $pdo;
private function __construct()
{
$this->pdo = new PDO(
"mysql:host=localhost;dbname=myapp",
"root",
"password",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
}
public static function getInstance(): Database
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getConnection(): PDO
{
return $this->pdo;
}
// 防止克隆和反序列化
private function __clone() {}
public function __wakeup() { throw new Exception("Cannot unserialize"); }
}
// 使用
$db = Database::getInstance()->getConnection();
$stmt = $db->query("SELECT * FROM users");
二、工厂模式
工厂模式将对象的创建逻辑封装起来,调用者不需要知道具体创建了哪个类的实例。它分为三种:简单工厂、工厂方法和抽象工厂。
// 支付系统 - 工厂模式
interface PaymentGateway
{
public function pay(float $amount): array;
public function refund(string $transactionId): array;
}
class AlipayGateway implements PaymentGateway
{
public function pay(float $amount): array
{
// 调用支付宝API
return ["gateway" => "alipay", "amount" => $amount, "status" => "success"];
}
public function refund(string $transactionId): array
{
return ["gateway" => "alipay", "refund_id" => $transactionId, "status" => "success"];
}
}
class WechatGateway implements PaymentGateway
{
public function pay(float $amount): array
{
return ["gateway" => "wechat", "amount" => $amount, "status" => "success"];
}
public function refund(string $transactionId): array
{
return ["gateway" => "wechat", "refund_id" => $transactionId, "status" => "success"];
}
}
// 工厂类
class PaymentFactory
{
public static function create(string $type): PaymentGateway
{
return match($type) {
"alipay" => new AlipayGateway(),
"wechat" => new WechatGateway(),
default => throw new InvalidArgumentException("不支持的支付方式: $type")
};
}
}
// 使用 - 调用者不需要知道具体实现
$gateway = PaymentFactory::create("alipay");
$result = $gateway->pay(99.99);
三、策略模式
策略模式定义一系列算法,将每个算法封装起来,并使它们可以互相替换。它让算法的变化独立于使用算法的客户端。
// 价格计算策略
interface PricingStrategy
{
public function calculate(float $originalPrice): float;
}
class RegularPricing implements PricingStrategy
{
public function calculate(float $originalPrice): float
{
return $originalPrice;
}
}
class DiscountPricing implements PricingStrategy
{
public function __construct(private float $discount) {}
public function calculate(float $originalPrice): float
{
return $originalPrice * $this->discount;
}
}
class MemberPricing implements PricingStrategy
{
public function calculate(float $originalPrice): float
{
return $originalPrice * 0.8; // 会员八折
}
}
// 上下文类
class Order
{
private PricingStrategy $pricingStrategy;
public function setPricingStrategy(PricingStrategy $strategy): void
{
$this->pricingStrategy = $strategy;
}
public function calculateTotal(float $price): float
{
return $this->pricingStrategy->calculate($price);
}
}
// 使用 - 运行时切换策略
$order = new Order();
// 普通用户
$order->setPricingStrategy(new RegularPricing());
echo $order->calculateTotal(100); // 100
// 促销打七折
$order->setPricingStrategy(new DiscountPricing(0.7));
echo $order->calculateTotal(100); // 70
// 会员价格
$order->setPricingStrategy(new MemberPricing());
echo $order->calculateTotal(100); // 80
四、三种模式的对比
| 模式 | 目的 | 解决的问题 | 应用场景 |
|---|---|---|---|
| 单例 | 控制实例数量 | 避免重复创建资源密集型对象 | 数据库连接、配置、日志 |
| 工厂 | 封装创建逻辑 | 解耦对象创建与使用 | 支付网关、通知渠道 |
| 策略 | 封装算法族 | 消除条件分支,支持运行时切换 | 价格计算、排序算法 |
设计模式不是银弹,不要为了使用模式而使用。当你在代码中看到大量if-else或switch-case分支时,可以考虑策略模式;当创建对象的逻辑变得复杂时,考虑引入工厂模式;当你需要全局唯一的资源管理时,使用单例模式。合理运用设计模式,可以让代码更加灵活、可测试和可维护。