规格模式(Specification Pattern)(C++ 实现)

规格模式(Specification Pattern)是一种行为设计模式,用于将业务规则封装成可重用的逻辑单元,支持通过组合方式构建复杂查询条件。核心思想是将条件判断逻辑抽象为独立对象,实现解耦和灵活组合。

核心组件
  1. ISpecification 接口
    定义 isSatisfiedBy 方法,验证对象是否满足条件
  2. 具体规格类
    实现特定业务规则(如价格、类别等)
  3. 组合规格类
    实现逻辑组合(AND/OR/NOT)
  4. 客户端
    组合规格对象进行业务判断

C++ 实现示例

场景:电商产品过滤系统

根据价格、类别、库存等条件筛选产品

#include <iostream>
#include <vector>
#include <string>
#include <memory>

// 1. 产品类
class Product {
public:
    Product(std::string name, double price, std::string category, int stock)
        : name(name), price(price), category(category), stock(stock) {}

    std::string getName() const { return name; }
    double getPrice() const { return price; }
    std::string getCategory() const { return category; }
    int getStock() const { return stock; }

private:
    std::string name;
    double price;
    std::string category;
    int stock;
};

// 2. 规格接口
template <typename T>
class ISpecification {
public:
    virtual ~ISpecification() = default;
    virtual bool isSatisfiedBy(const T& item) const = 0;
};

// 3. 具体规格实现
// 价格规格
class PriceSpecification : public ISpecification<Product> {
public:
    PriceSpecification(double minPrice, double maxPrice)
        : minPrice(minPrice), maxPrice(maxPrice) {}

    bool isSatisfiedBy(const Product& item) const override {
        return item.getPrice() >= minPrice && item.getPrice() <= maxPrice;
    }

private:
    double minPrice;
    double maxPrice;
};

// 类别规格
class CategorySpecification : public ISpecification<Product> {
public:
    explicit CategorySpecification(std::string category)
        : category(std::move(category)) {}

    bool isSatisfiedBy(const Product& item) const override {
        return item.getCategory() == category;
    }

private:
    std::string category;
};

// 库存规格
class StockSpecification : public ISpecification<Product> {
public:
    explicit StockSpecification(int minStock) : minStock(minStock) {}

    bool isSatisfiedBy(const Product& item) const override {
        return item.getStock() >= minStock;
    }

private:
    int minStock;
};

// 4. 组合规格 (AND)
template <typename T>
class AndSpecification : public ISpecification<T> {
public:
    AndSpecification(std::shared_ptr<ISpecification<T>> left, 
                     std::shared_ptr<ISpecification<T>> right)
        : left(std::move(left)), right(std::move(right)) {}

    bool isSatisfiedBy(const T& item) const override {
        return left->isSatisfiedBy(item) && right->isSatisfiedBy(item);
    }

private:
    std::shared_ptr<ISpecification<T>> left;
    std::shared_ptr<ISpecification<T>> right;
};

// 5. 组合规格 (OR)
template <typename T>
class OrSpecification : public ISpecification<T> {
public:
    OrSpecification(std::shared_ptr<ISpecification<T>> left, 
                    std::shared_ptr<ISpecification<T>> right)
        : left(std::move(left)), right(std::move(right)) {}

    bool isSatisfiedBy(const T& item) const override {
        return left->isSatisfiedBy(item) || right->isSatisfiedBy(item);
    }

private:
    std::shared_ptr<ISpecification<T>> left;
    std::shared_ptr<ISpecification<T>> right;
};

// 6. 使用示例
int main() {
    // 创建产品列表
    std::vector<Product> products = {
        {"Laptop", 1200.0, "Electronics", 5},
        {"Book", 15.99, "Books", 20},
        {"Headphones", 99.99, "Electronics", 0},
        {"Monitor", 250.0, "Electronics", 8},
        {"Coffee Mug", 8.5, "Kitchen", 30}
    };

    // 创建规格对象
    auto electronicsSpec = std::make_shared<CategorySpecification>("Electronics");
    auto priceSpec = std::make_shared<PriceSpecification>(100.0, 300.0);
    auto stockSpec = std::make_shared<StockSpecification>(5);

    // 组合规格:电子类 AND (价格在$100-$300之间 OR 库存>5)
    auto complexSpec = std::make_shared<AndSpecification<Product>>(
        electronicsSpec,
        std::make_shared<OrSpecification<Product>>(priceSpec, stockSpec)
    );

    // 应用规格过滤
    std::cout << "Filtered Products:\n";
    for (const auto& product : products) {
        if (complexSpec->isSatisfiedBy(product)) {
            std::cout << "- " << product.getName() 
                      << " ($" << product.getPrice()
                      << ", Stock: " << product.getStock() << ")\n";
        }
    }

    return 0;
}
输出结果
Filtered Products:
- Monitor ($250, Stock: 8)

模式优势

  1. 解耦业务规则
    将条件判断从业务逻辑中分离
  2. 可重用性
    规格对象可在不同场景复用
  3. 灵活组合
    通过 AND/OR/NOT 构建复杂查询
  4. 可测试性
    每个规格可独立测试
  5. 扩展性
    新增规格不影响现有代码

适用场景

  • 复杂条件过滤系统
  • 验证规则需要动态组合
  • 数据库查询条件构建
  • 需要高度可配置的业务规则
  • 领域驱动设计(DDD)中的规范模式
对比传统方法
传统 if-else 方式规格模式
条件逻辑与业务代码耦合业务规则独立封装
修改条件需改动核心逻辑通过组合新规格扩展
复杂条件可读性差声明式组合,逻辑清晰
重复条件难以复用规格对象全局复用

推荐阅读

更多推荐