设计模式

设计模式分类:

  • 创建型:单例模式;工厂模式;抽象工厂模式;建造者模式;
  • 结构性:适配器模式;装饰器模式;门面模式;
  • 行为型:策略模式;观察者模式;责任链模式;
  • 架构型:注册模式

image

 

  • | 单例模式:确保一个类只有一个实例。(优点:全局只有一个入口点,易维。节省资源。缺点:测试困难)
  • l 工厂模式:定义创建对象的接口,由子类决定实例化那个类(优点:单一职责;缺点:类数量膨胀)
  • l 抽象工厂模式:提供接口创建一系列相关或者以来的对象,无需指定具体类(优点:产品一致性;缺点:扩展困难)
  • l 策略模式:定义算法族,封装并互换,让算法独立于使用它的客户端(优点:避免大量if-else,开闭原则;缺点:类数量多,客户端需要知道策略)
  • l 观察者模式:当一个对象状态发生变化时,依赖它的对象会受到通知并自动更新(优点:松耦合;缺点:类数不好确定)
  • l 装饰器模式:动态给对象添加功能,不改变原有类,适用于扩展功能(优点:灵活扩展;缺点:多层嵌套)
  • | 注册模式:解决全局共享和交换对象,将对象注册到全局数组,需要时直接获取(优点:集中管理,动态扩展;缺点:全局扩展,测试困难)
  • l 适配器模式:兼容不同接口,让不能兼容的类一起调用(优点:兼容性好;缺点:增加复杂度)
  • l 建造者模式:分布构建复杂对象,避免构造函数参数过多(优点:链式调用,参数校验;缺点:代码冗余)
  • | 责任链模式:请求传递,解耦发送者和接收者。(优点:解耦发送者和接收者,灵活职责分配;缺点:调试困难,性能损耗)

设计模式详情&场景样例:

一. 单例模式:

确保一个类只有一个实例,常用于全局资源管理

好处

节省资源:避免重复连接数据库;统一管理:所有数据库操作通过同一入口;易于维护:修改连接配置只需改一处;性能优化:减少 TCP 握手和认证开销

1.数据库连接场景:

<?php
class Database {
    private static $instance = null;
    private $connection;
    
    // 私有化构造方法,防止外部 new
    private function __construct() {
        try {
            $this->connection = new PDO(
                "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
                DB_USER,
                DB_PASS,
                [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                    PDO::ATTR_PERSISTENT => false  // 是否持久连接
                ]
            );
        } catch (PDOException $e) {
            die("数据库连接失败: " . $e->getMessage());
        }
    }
    
    // 私有化克隆方法,防止克隆
    private function __clone() {}
    
    // 私有化反序列化方法,防止反序列化
    private function __wakeup() {}
    
    // 获取单例实例
    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    // 获取数据库连接
    public function getConnection(): PDO {
        return $this->connection;
    }
    
    // 执行查询
    public function query($sql, $params = []) {
        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }
    
    
    // 插入数据
    public function insert($table, $data) {
        $fields = array_keys($data);
        $placeholders = ':' . implode(', :', $fields);
        $sql = "INSERT INTO {$table} (" . implode(',', $fields) . ") VALUES ({$placeholders})";
        
        $stmt = $this->connection->prepare($sql);
        return $stmt->execute($data);
    }
}

// ------------------使用示例--------------------
$db = Database::getInstance();
$connection = $db->getConnection();

// 查询
$users = $db->query("SELECT * FROM users WHERE status = ?", [1]);

// 插入
$db->insert('users', [
    'name' => '阿陌',
    'email' => 'amo@111.com'
]);
?>

2.购物车场景(确保用户购物车全局唯一)

<?php
	class Cart {
	    private static $instance = null;
	    private $items = [];
	    
	    // 私有化构造,防止外部 new
	    private function __construct() {}
	    private function __clone() {}
	    
	    public static function getInstance(): self {
	        if (self::$instance === null) {
	            self::$instance = new self();
	        }
	        return self::$instance;
	    }
	    
	    public function addItem($productId, $quantity) {
	        $this->items[$productId] = ($this->items[$productId] ?? 0) + $quantity;
	    }
	    
	    public function getItems() {
	        return $this->items;
	    }
	}

//-------------使用样例-----------------

// 使用:无论调用多少次,都是同一个购物车实例
$cart = Cart::getInstance();
$cart->addItem(1001, 2);

$cart2 = Cart::getInstance();
$cart2->addItem(1002, 1);

var_dump($cart === $cart2); // true
?>

二. 工厂模式

封装对象创建逻辑,解耦调用方和具体类。

1.促销场景: 

<?php

// 促销接口
interface Promotion {
    public function calculate($originalPrice);
    public function getDescription();
}

// 满减促销
class FullReductionPromotion implements Promotion {
    private $threshold;  // 满多少
    private $reduction;  // 减多少
    
    public function __construct($threshold, $reduction) {
        $this->threshold = $threshold;
        $this->reduction = $reduction;
    }
    
    public function calculate($originalPrice) {
        if ($originalPrice >= $this->threshold) {
            return $originalPrice - $this->reduction;
        }
        return $originalPrice;
    }
    
    public function getDescription() {
        return "满 {$this->threshold} 减 {$this->reduction}";
    }
}

// 折扣促销
class DiscountPromotion implements Promotion {
    private $discount;  // 折扣率,如 0.8 表示 8 折
    
    public function __construct($discount) {
        $this->discount = $discount;
    }
    
    public function calculate($originalPrice) {
        return $originalPrice * $this->discount;
    }
    
    public function getDescription() {
        return $this->discount * 10 . "折";
    }
}


// 第二件半价
class SecondHalfPromotion implements Promotion {
    public function calculate($originalPrice) {
        // 需要结合数量实现,这里简化
        return $originalPrice;
    }
    
    public function getDescription() {
        return "第二件半价";
    }
}

// 促销工厂
class PromotionFactory {
    public static function create($type, $config): Promotion {
        switch ($type) {
            case 'full_reduction':
                return new FullReductionPromotion(
                    $config['threshold'],
                    $config['reduction']
                );
            case 'discount':
                return new DiscountPromotion($config['discount']);
            case 'second_half':
                return new SecondHalfPromotion();
            default:
                throw new Exception("不支持的促销类型: {$type}");
        }
    }
}

// ----------------使用示例:创建多种促销活动------------- $promotions = [ PromotionFactory::create('full_reduction', ['threshold' => 200, 'reduction' => 30]), PromotionFactory::create('discount', ['discount' => 0.85]), PromotionFactory::create('flash_sale', ['sale_price' => 99, 'limit' => 2]), ]; $price = 300; foreach ($promotions as $promo) { echo $promo->getDescription() . " 最终价: " . $promo->calculate($price) . "\n"; }

2. 物流服务场景:

<?php

interface Logistics {
    public function createOrder($orderInfo);
    public function calculateFee($weight, $destination);
}

class SFLogistics implements Logistics {
    
    public function __construct() {
    }
    
    public function createOrder($orderInfo) {
        // 顺丰下单 API 调用
        return true;
    }
    
    public function calculateFee($weight, $destination) {
        // 顺丰计价规则:首重 12 元,续重 2 元/kg
        $fee = 12 + max(0, $weight - 1) * 2;
        
        // 偏远地区加价
        $remoteAreas = ['新疆', '西藏', '内蒙古'];
        if (in_array($destination, $remoteAreas)) {
            $fee += 10;
        }
        
        return $fee;
    }
}

class JDLogistics implements Logistics {
    public function createOrder($orderInfo) {
        // 京东物流 API
        return "京东物流单号: JD" . time();
    }
    
    public function calculateFee($weight, $destination) {
        // 京东物流计价:首重 10 元,续重 1.8 元/kg
        return 10 + $weight * 1.8;
    }
}

// 物流工厂
class LogisticsFactory {
    private static $providers = [
        'sf' => SFLogistics::class,
        'jd' => JDLogistics::class,
    ];
    
    public static function create($providerCode): Logistics {
        if (!isset(self::$providers[$providerCode])) {
            throw new Exception("不支持的物流商: {$providerCode}");
        }
        
        $className = self::$providers[$providerCode];
        return new $className();
    }
    
    // 根据用户地址智能选择最优物流商
    public static function getBestProvider($address, $weight): Logistics {
        // 智能推荐逻辑
        if (strpos($address, '北京') !== false && $weight > 10) {
            // 北京地区大件用京东物流
            return self::create('jd');
        }
        //else if 其他物流逻辑
        else {
            // 默认顺丰(服务好)
            return self::create('sf');
        }
    }
}

//---------- 使用示例-------------

//获取运费
class ShippingService {
    public function calculateShippingFee($orderId, $address, $weight) {
        // 智能选择物流商
        $logistics = LogisticsFactory::getBestProvider($address, $weight);
        $fee = $logistics->calculateFee($weight, $address);
        
        // 保存到订单
        Order::where('id', $orderId)->update([
            'shipping_fee' => $fee,
            'logistics_provider' => get_class($logistics)
        ]);
        
        return $fee;
    }
    
//发货
    public function shipOrder($orderId, $providerCode) {
        $order = Order::find($orderId);
        $logistics = LogisticsFactory::create($providerCode);
        
        $trackingNumber = $logistics->createOrder([
            'order_no' => $order->order_no,
            'address' => $order->shipping_address,
            'weight' => $order->weight
        ]);
        
        $order->tracking_number = $trackingNumber;
        $order->status = 'shipped';
        $order->save();
        
        return $trackingNumber;
    }
}

3.批量导入导出场景

 

<?php

interface ImportExport {
    public function export($data, $filePath);
}

class CSVHandler implements ImportExport {
    public function export($data, $filePath) {
        $handle = fopen($filePath, 'w');
        
        // 写入表头
        if (!empty($data)) {
            fputcsv($handle, array_keys($data[0]));
            
            // 写入数据
            foreach ($data as $row) {
                fputcsv($handle, $row);
            }
        }
        
        fclose($handle);
        return true;
    }
}

class ExcelHandler implements ImportExport {
    public function export($data, $filePath) {
        $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        
        // 写入表头
        $col = 'A';
        foreach (array_keys($data[0]) as $header) {
            $sheet->setCellValue($col . '1', $header);
            $col++;
        }
        
        // 写入数据
        $row = 2;
        foreach ($data as $item) {
            $col = 'A';
            foreach ($item as $value) {
                $sheet->setCellValue($col . $row, $value);
                $col++;
            }
            $row++;
        }
        
        $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
        $writer->save($filePath);
        
        return true;
    }
}

// 导出工厂
class ImportExportFactory {
    public static function create($format): ImportExport {
        switch (strtolower($format)) {
            case 'csv':
                return new CSVHandler();
            case 'xlsx':
            case 'xls':
                return new ExcelHandler();
            default:
                throw new Exception("不支持的格式: {$format}");
        }
    }
}

//------------使用示例:批量导出--------
class ProductImportService {
    
    public function export($productIds, $format) {
        $data = [];//导出的数据列表
        $handler = ImportExportFactory::create($format);
        
        $filePath = storage_path("exports/products_" . time() . ".{$format}");
        $handler->export($data, $filePath);
        
        return $filePath;
    }
}

  

三. 抽象工厂模式

创建一系列相关对象,比工厂模式更宏观。

1.订单导出器场景(多格式+多平台)

// 问题:需要导出不同格式(PDF、Excel)和不同平台(淘宝、京东)
interface OrderExportFactory {
    public function createHeader();
    public function createBody();
    public function createFooter();
}

// 淘宝 Excel 导出
class TaobaoExcelFactory implements OrderExportFactory {
    public function createHeader() { return new TaobaoExcelHeader(); }
    public function createBody()   { return new TaobaoExcelBody(); }
    public function createFooter() { return new TaobaoExcelFooter(); }
}

// 京东 PDF 导出
class JingdongPDFFactory implements OrderExportFactory {
    public function createHeader() { return new JingdongPDFHeader(); }
    public function createBody()   { return new JingdongPDFBody(); }
    public function createFooter() { return new JingdongPDFFooter(); }
}

// -------------------使用场景--------------------------
function exportOrders(OrderExportFactory $factory) { $header = $factory->createHeader(); $body = $factory->createBody(); $footer = $factory->createFooter(); return $header->render() . $body->render() . $footer->render(); } $export = exportOrders(new TaobaoExcelFactory()); // 淘宝 Excel $export = exportOrders(new JingdongPDFFactory()); // 京东 PDF

四. 策略模式

 定义一系列算法,动态切换

商品多维度推荐列表场景:

<?php

// 推荐策略接口
interface RecommendStrategy {
    public function recommend($userId, $limit = 10);
}

// 基于浏览历史的推荐
class HistoryBasedRecommend implements RecommendStrategy {
    public function recommend($userId, $limit = 10) {
        // 获取用户浏览历史
        $viewedProducts = ProductView::where('user_id', $userId)
            ->orderBy('viewed_at', 'desc')
            ->limit(20)
            ->pluck('product_id');
        
        // 找到同分类的商品
        $categories = Product::whereIn('id', $viewedProducts)
            ->pluck('category_id');
        
        $recommendations = Product::whereIn('category_id', $categories)
            ->whereNotIn('id', $viewedProducts)
            ->inRandomOrder()
            ->limit($limit)
            ->get();
        
        return $recommendations;
    }
}


// 热门商品推荐
class HotProductsRecommend implements RecommendStrategy {
    public function recommend($userId, $limit = 10) {
        return Product::where('status', 1)
            ->orderBy('sale_count', 'desc')
            ->limit($limit)
            ->get();
    }
}

// 新品推荐
class NewArrivalRecommend implements RecommendStrategy {
    public function recommend($userId, $limit = 10) {
        return Product::where('status', 1)
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get();
    }
}

// 个性化推荐(组合多种策略)
class PersonalizedRecommend implements RecommendStrategy {
    private $strategies = [];
    
    public function __construct() {
        $this->strategies = [
            new HistoryBasedRecommend(),
            new HotProductsRecommend()
        ];
    }
    
    public function recommend($userId, $limit = 10) {
        $allRecommendations = collect();
        
        foreach ($this->strategies as $strategy) {
            $recs = $strategy->recommend($userId, $limit);
            $allRecommendations = $allRecommendations->merge($recs);
        }
        
        // 去重并排序
        return $allRecommendations->unique('id')
            ->take($limit);
    }
}

// 推荐上下文
class RecommendEngine {
    private $strategy;
    
    public function setStrategy(RecommendStrategy $strategy) {
        $this->strategy = $strategy;
        return $this;
    }
    
    public function getRecommendations($userId, $limit = 10) {
        $startTime = microtime(true);
        $results = $this->strategy->recommend($userId, $limit);
        $duration = microtime(true) - $startTime;
        
        // 记录推荐日志
        Log::info("推荐策略执行", [
            'strategy' => get_class($this->strategy),
            'user_id' => $userId,
            'count' => $results->count(),
            'duration' => $duration
        ]);
        
        return $results;
    }
}

// ---------------使用示例---------------------
class HomeController {
    public function index(Request $request) {
        $userId = auth()->id();
        $recommendEngine = new RecommendEngine();
        
        // 根据场景选择策略
        if ($request->get('tab') === 'hot') {
            $recommendEngine->setStrategy(new HotProductsRecommend());
        } elseif ($request->get('tab') === 'new') {
            $recommendEngine->setStrategy(new NewArrivalRecommend());
        } elseif (Cache::has("user_profile:{$userId}")) {
            // 有用户画像,使用个性化推荐
            $recommendEngine->setStrategy(new PersonalizedRecommend());
        } else {
            // 新用户,使用浏览历史推荐
            $recommendEngine->setStrategy(new HistoryBasedRecommend());
        }
        
        $products = $recommendEngine->getRecommendations($userId, 20);
        
        return view('goods', ['products' => $products]);
    }
}

五. 观察者模式

 事件驱动,一对多依赖。

订单状态通知场景:

interface Observer {
    public function update($event, $data);
}

// 短信通知
class SMSNotifier implements Observer {
    public function update($event, $data) {
        if ($event == 'order.paid') {
            echo "发送短信给用户 {$data['user_id']}: 订单支付成功\n";
        }
    }
}

// 邮件通知
class EmailNotifier implements Observer {
    public function update($event, $data) {
        if ($event == 'order.shipped') {
            echo "发送邮件给用户 {$data['user_id']}: 订单已发货\n";
        }
    }
}

// 库存更新
class InventoryUpdater implements Observer {
    public function update($event, $data) {
        if ($event == 'order.cancelled') {
            echo "恢复库存: 商品 {$data['product_id']} 数量 {$data['quantity']}\n";
        }
    }
}


class Order {
    private $observers = [];
    
    public function attach(Observer $observer) {
        $this->observers[] = $observer;
    }
    
    public function notify($event, $data) {
        foreach ($this->observers as $observer) {
            $observer->update($event, $data);
        }
    }
    
    public function pay($userId, $orderId) {
        // 支付逻辑
        $this->notify('order.paid', [
            'user_id' => $userId,
            'order_id' => $orderId,
            'points' => 100,
        ]);
    }
    
}

// ---------------使用方式------------
$order = new Order();
$order->attach(new SMSNotifier());
$order->attach(new EmailNotifier());
$order->attach(new InventoryUpdater());

$order->pay(10086, 'ORDER123');
// 输出:
// 发送短信给用户 10086: 订单支付成功

  

 

六. 责任链模式:

 多个对象处理同一个请求,避免if-else堆积

商品审核场景:

<?php

// 审核处理器抽象类
abstract class ReviewHandler {
    protected $next;
    protected $level;
    
    public function setNext(ReviewHandler $handler) {
        $this->next = $handler;
        return $handler;
    }
    
    public function handle($product) {
        if ($this->canHandle($product)) {
            $result = $this->process($product);
            if ($result === false) {
                return false;
            }
        }
        
        if ($this->next) {
            return $this->next->handle($product);
        }
        
        return true;
    }
    
    abstract protected function canHandle($product);
    abstract protected function process($product);
}

// 商品信息审核(自动审核)
class InfoReviewHandler extends ReviewHandler {
    protected $level = 1;
    
    protected function canHandle($product) {
        return true; // 所有商品都需要基础信息审核
    }
    
    protected function process($product) {
        $errors = [];
        
        // 检查商品名称
        if (strlen($product->name) < 2 || strlen($product->name) > 100) {
            $errors[] = "商品名称长度必须在2-100之间";
        }
        
        // 检查价格
        if ($product->price <= 0 || $product->price > 100000) {
            $errors[] = "商品价格必须在0-100000之间";
        }
        
        // 检查库存
        if ($product->stock < 0) {
            $errors[] = "库存不能为负数";
        }
        
        // 检查描述
        if (empty($product->description)) {
            $errors[] = "商品描述不能为空";
        }
        
        if (!empty($errors)) {
            $product->review_status = 'failed';
            $product->review_reason = implode('; ', $errors);
            $product->save();
            return false;
        }
        
        return true;
    }
}

// 图片审核(机审+人审)
class ImageReviewHandler extends ReviewHandler {
    protected $level = 2;
    
    protected function canHandle($product) {
        return !empty($product->images);
    }
    
    protected function process($product) {
        // 调用图片审核API
        $apiResult = ImageModeration::check($product->images);
        
        if ($apiResult['has_illegal']) {
            $product->review_status = 'failed';
            $product->review_reason = "商品图片包含违规内容: {$apiResult['reason']}";
            $product->save();
            return false;
        }
        
        // 疑似违规进入人工审核
        if ($apiResult['is_suspicious']) {
            $product->review_status = 'manual';
            $product->review_reason = "图片疑似违规,需人工审核";
            $product->save();
            return false;
        }
        
        return true;
    }
}


// 价格审核(价格异常需人工审核)
class PriceReviewHandler extends ReviewHandler {
    protected $level = 4;
    
    protected function canHandle($product) {
        // 价格低于成本价50%或高于市场价200%
        $costPrice = $product->cost_price;
        $marketPrice = $this->getMarketPrice($product->category_id);
        
        return $product->price < $costPrice * 0.5 || $product->price > $marketPrice * 2;
    }
    
    protected function process($product) {
        $product->review_status = 'manual';
        $product->review_reason = "价格异常,需人工审核";
        $product->save();
        
        // 发送通知给运营人员
        Notification::send('运营组', "商品 {$product->name} 价格异常");
        
        return false;
    }
    
    private function getMarketPrice($categoryId) {
        // 获取该类目的平均市场价
        return Product::where('category_id', $categoryId)
            ->avg('price') ?? 100;
    }
}



// -----------使用示例:商品审核服务--------
class ProductReviewService {
    public function review($productId) {
        $product = Product::find($productId);
        
        // 构建责任链
        $infoHandler = new InfoReviewHandler();
        $imageHandler = new ImageReviewHandler();
        $priceHandler = new PriceReviewHandler();
        
        $infoHandler->setNext($imageHandler)
                    ->setNext($priceHandler);
        
        $result = $infoHandler->handle($product);
        
        if ($result && $product->review_status !== 'manual') {
            $product->review_status = 'approved';
            $product->reviewed_at = now();
            $product->save();
            
            // 上架商品
            $product->status = 'on';
            $product->save();
        }
        
        return $product->review_status;
    }
}

  

七. 适配器模式

兼容不同接口,让不兼容的类能一起工作。

多仓库商品同步场景:

内容都是商品名|价格|数量|主图,但是每个供应商仓库对应的传参格式/传参名/传参内容

 
// 问题:仓库1,仓库2,仓库3,API 不同,需要统一接口
interface ProductSync {
    public function sync($product);
}

// 仓库1适配器
class WareHouseAdapter1 implements ProductSync {
    private $warehouseAPI;
    
    public function __construct() {
        $this->warehouseAPI = new WareHouseAPI();
    }
    
    public function sync($product) {
        // 转换数据格式
        $data = [
            'title' => $product->name,
            'price' => $product->price,
            'stock' => $product->quantity,
            'pic' => $product->pic_link,
        ];
        return $this->warehouseAPI->uploadProduct($data);
    }
}

// 仓库2适配器
class WareHouseAdapter2 implements ProductSync {
    private $wHAPI;
    
    public function __construct() {
        $this->wHAPI = new WhAPI();
    }
    
    public function sync($product) {
        // 仓库2API传参格式不同,方法名也不同
        $data = [
            'sku_name' => $product->name,
            'sale_price' => $product->price,
            'quantity' => $product->quantity,
        ];
        return $this->wHAPI->createGood($data);
    }
}

// --------------使用:统一调用--------------------
function syncToAllPlatforms($product) {
    $adapters = [
        new WareHouseAdapter1(),
        new WareHouseAdapter2(),
    ];
    
    foreach ($adapters as $adapter) {
        $adapter->sync($product);
    }
}

  

八. 建造者模式:

分步构建复杂对象,避免构造函数参数过多。

1.构建XX表(商品表)搜索条件场景:

 
// 问题:商品搜索有几十个参数,构造函数难以维护
class ProductSearchBuilder {
    private $params = [];
    
    //关键词搜索
    public function setKeyword($keyword) {
        $this->params['keyword'] = $keyword;
        return $this; 
    }
    //……其他维度搜索按业务需求补充……
    
    //价格区间搜索
    public function setPriceRange($min, $max) {
        $this->params['price_min'] = $min;
        $this->params['price_max'] = $max;
        return $this;
    }
    //排序
    public function setSort($field, $order = 'asc') {
        $this->params['sort'] = $field;
        $this->params['order'] = $order;
        return $this;
    }
    
    //分页
    public function setPage($page, $size = 20) {
        $this->params['page'] = $page;
        $this->params['size'] = $size;
        return $this;
    }
    
    public function build() {
        return new ProductSearchQuery($this->params);
    }
}

// ----使用方式:清晰直观----
$searchQuery = (new ProductSearchBuilder())
    ->setKeyword('手机')
    //->setCategory(100)->setPriceRange(1000, 5000)
    ->setSort('price', 'desc')
    ->setPage(1, 20)
    ->build();

  

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2021-04-21 17:37  阿陌i  阅读(6)  评论(0)    收藏  举报