C++ 开闭原则代码例子 Open/Closed Principle

// Open-closed Principle
// entities should be open for extension, but closed for modification

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

enum class Color { Red, Green, Blue };
enum class Size { Small, Medium, Large };

struct Product {
    std::string name;
    Color color;
    Size size;
};

typedef std::vector<Product> ProductList;

// This is how not to do it.
// To add new criteria you have to go into this class again and change and also test it.
// Violates the Open-closed Principle.
struct ProductFilter {
    static ProductList by_color(ProductList items, Color color) {
        ProductList result;
        for (auto& item : items)
            if (item.color == color) result.push_back(item);
        return result;
    }

    static ProductList by_size(ProductList items, Size Size) {
        ProductList result;
        for (auto& i : items)
            if (i.size == Size) result.push_back(i);
        return result;
    }

    // Not scalable !!!
    // We'd need all combinations of possible filter criteria.
    static ProductList by_color_and_size(ProductList items, Color color, Size size) {
        ProductList result;
        for (auto& item : items)
            if (item.color == color && item.size == size) result.push_back(item);
        return result;
    }
};

// Better: Generalize with interfaces
// Specification pattern. Not a GoF pattern but extensively used.
// Reminds of generative programming (GP).
// it's an interface = class with virtual functions
// generic specification
template <typename T>
struct ISpecification {
    virtual bool is_satisfied(T item) = 0;
};

// we can combine specifications
template <typename T>
struct AndSpecification : ISpecification<T> {
    ISpecification<T>& first;
    ISpecification<T>& second;

    AndSpecification(ISpecification<T>& first, ISpecification<T>& second)
        : first{ first }, second{ second } {}

    bool is_satisfied(T item) override {
        return first.is_satisfied(item) && second.is_satisfied(item);
    }
};

// ColorSpecification is a product specification
struct ColorSpecification : ISpecification<Product> {
    Color color;

    explicit ColorSpecification(const Color color) : color{ color } {}

    bool is_satisfied(Product item) override { return item.color == color; }
};

// SizeSpecification is a product specification
struct SizeSpecification : ISpecification<Product> {
    Size size;

    explicit SizeSpecification(const Size size) : size{ size } {}

    bool is_satisfied(Product item) override { return item.size == size; }
};

// another interface that uses the specification interface
// generic filter
template <typename T>
struct IFilter {
    // try to pass spec by value and you end up in OO hell!
    virtual ProductList filter(ProductList& items, ISpecification<T>& spec) = 0;
};

// BetterFilter is a product filter
struct BetterFilter : IFilter<Product> {
    ProductList filter(ProductList& items, ISpecification<Product>& spec) override {
        ProductList result;
        for (auto& productItem : items)
            if (spec.is_satisfied(productItem)) result.push_back(productItem);
        return result;
    }
};

int main() {
    Product apple{ "Apple", Color::Green, Size::Small };
    Product tree{ "Tree", Color::Green, Size::Large };
    Product house{ "House", Color::Blue, Size::Large };

    ProductList all{ apple, tree, house };

    BetterFilter bf;
    ColorSpecification green(Color::Green);

    auto green_things = bf.filter(all, green);
    for (auto& product : green_things)
        std::cout << product.name << " is green" << std::endl;

    SizeSpecification big(Size::Large);
    // green_and_big is a product specification
    AndSpecification<Product> green_and_big{ big, green };

    auto green_big_things = bf.filter(all, green_and_big);
    for (auto& product : green_big_things)
        std::cout << product.name << " is green and big" << std::endl;

    return 0;
}

转载自https://raw.githubusercontent.com/schmidh/CPP-Design-Patterns/master/1-Creational/1-Design-Principles/1-SOLID/2-O-penClosedPrinciple/OCP.cpp

首先是一般的写法

ProductFilter在过滤时,有多少个过滤选项就在类中写硬代码,这样每次需要改写过滤参数的个数,如下:
在这里插入图片描述
每次增加新的需求都需要改变代码,不符合开闭原则中的“闭”

更好的写法

使用了接口,实现接口的时候在接口中写具体的处理代码。过滤器BetterFilter只需调用实现好的接口,而不用关心接口是如何实现的。如下:
在这里插入图片描述
在C++中实现好的接口是接口的子类,所以BetterFilter中可以直接使用父类指向子类的指针来调用子类(实现好的接口)。
这样每次增加新的需求时,只需要重新实现一个接口,无需修改原来的代码。
做到了开闭原则的"开":可以扩展。“闭”:不修改原有代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C++ 的设计模式并没有八大原则,但是设计模式中常用的一些原则包括以下几个: 1. 开闭原则Open-Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。 2. 单一职责原则(Single Responsibility Principle,SRP):一个类只负责一个功能或者只有一个引起它变化的原因。 3. 里氏替换原则(Liskov Substitution Principle,LSP):子类必须能够替换掉它们的父类并且保持程序的正确性。 4. 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖于底层模块,两者都应该依赖于抽象。 5. 接口隔离原则(Interface Segregation Principle,ISP):不应该强迫客户端依赖于它们不需要的接口。 6. 组合/聚合复用原则(Composite/Aggregate Reuse Principle,CARP):优先使用组合或聚合关系复用代码,而不是继承。 7. 迪米特法则(Law of Demeter,LoD):一个对象应该对其他对象有最少的了解,不和陌生人说话,只和你的朋友(也就是直接的朋友)通信。 8. 最少知识原则(Least Knowledge Principle,LKP):一个软件实体应当尽可能少地与其他实体发生相互作用,使得系统中的各个部分更独立。 这些原则都是为了提高代码的可维护性、可扩展性、可重用性和可测试性,是面向对象设计和编程中非常重要的基本原则。在实际的软件开发中,应该根据具体的情况选择合适的原则进行应用。同时,这些原则也是设计模式的基础,很多设计模式都是基于这些原则的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值