SOLID 代码设计原则

C# 中的 SOLID 设计原则:构建可维护、可扩展的代码架构 一个类应该只有一个引起它变化的原因。单一职责原则强调类的职责要单一,避免将过多的功能耦合在一个类中。这样可以降低类的复杂度,提高代码的可维护性和复用性。当一个类承担的职责过多时,修改其中一个职责可能会影响其他职责,导致系统变得脆弱。软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。开闭原则是面向对象设计的核心目标之一。它要求我们在设计系统时,能够在不修改现有代码的情况下,通过扩展来增加新功能。这需要我们将系统的行为抽象成稳定的接口,而具体实现可以灵活变化。 阅读详情

不同于设计模式,在面向对象软件设计当中,还有 SOLID 代码设计原则,本文将对其进行介绍和举例。

1、什么是设计模式

设计模式是软件设计当中通用的、可复用的解决方案,它是关于如何在不同情况下如何解决问题的描述或模版,通常是最佳实践。

设计模式使得代码变得可维护的、可扩展的、解耦的,开发者为每个解决某种类型问题的方案起名,整理成各种通用的设计模式。

注意,软件架构和设计模式是不同的概念,软件架构描述的是要实现什么样的功能和在什么地方来实施,而设计模式是描述怎样来实现。

设计模式不是要编写解决方案,它更像是描述解决方案应该长什么样。在设计模式当中,问题及其解决方案是密不可分的。

我们需要设计模式,这样代码会更加清晰、直观、占用更少的内存空间、性能高效,也更加方便我们后续进行代码的修改。

设计模式主要包含 6 条规则:

  1. 经过验证和实践的(Proven Solutions)
  2. 可以简单地进行复用(Easily Reusable)
  3. 直观的(Expressive)
  4. 易于交流的(Ease Communication)
  5. 预防重构的需要(Prevent the Need for Refactoring Code)
  6. 最小化代码(Lower the Size of the Codebase)

当设计一个完整的软件应用时,我们需要考虑得很多:

  • 创建(Creational Design Patterns):如何创建或者实例化对象?(Factory、Builder、Prototype、Singleton)
  • 结构化(Structural Design Patterns):各个对象如何结合成一个大的实体,如何兼容未来的需要?(Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy)
  • 行为(Behavioural Design Patterns):对象之间如何联系,如何避免后续改动的影响以及减少副作用?(Chain of responsibility、Command、Interpreter、Iterator、Mediator、Memento、Observer、State、Strategy、Template Method、Visitor)

2、SOLID 设计原则

SOLID 是面向对象软件设计当中较为出名的一系列设计原则,包含有以下 5 个原则:

  • SRP – Single Responsibility Principle
  • OCP – Open/Closed Principle
  • LSP – Liskov Substitution Principle
  • ISP – Interface Segregation Principle
  • DIP – Dependency Inversion Principle

注:设计模式(Pattern)和设计原则(Principle) 是两个不同的概念。

2.1、Single Responsibility Principle (SRP)

SRP (单一功能原则),主要思想是一个类只能有一个被修改的原因(A class should have only one reason to change)。

也就是说每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。

class Journal {
    string          m_title;
    vector<string>  m_entries;

public:
    explicit Journal(const string &title) : m_title{title} {} 
    void add_entries(const string &entry) {
        static uint32_t count = 1;
        m_entries.push_back(to_string(count++) + ": " + entry);
    } 
    auto get_entries() const { return m_entries; }

    //void save(const string &filename)
    //{
    //    ofstream ofs(filename); 
    //    for (auto &s : m_entries) ofs << s << endl;
    //}
};

struct SavingManager {
    static void save(const Journal &j, const string &filename) {
        ofstream ofs(filename);
        for (auto &s : j.get_entries())
            ofs << s << endl;
    }
};

SavingManager::save(journal, "diary.txt");

在上面的代码案例中,Journal 类如果同时存在两个功能(two reason to change),关联事件(add_entries)和保存(save),那么会存在以下问题:

  • 如果要添加 Book、File 等类,需要为他们也实现各自的保存函数
  • 当要修改或维护保存函数时,需要去每个类实现当中去做判断

所以根据 SRP 设计原则,把保存函数抽离,封装成另一个类,这样 Journal 类只需要关联事件,而 SavingManager 类只负责保存,这样就可以应付后面的改动,提高可维护性、更直观、解耦、可复用。

但也会存在缺点,各个类之间可能会存在联系,导致上百个类关联到一起,实际应该整合成一个类。

SRP 原则是为了减少改动的影响,所以整合功能以相同的原因(same reason)做修改,分离功能是因为以不同的原因(different reason)做修改。在做代码重构时,非常有帮助。

2.2、Open Closed Principle (OCP)

OCP (开闭原则),主要思想是软件中的对象应该对于扩展是开放的,但是对于修改是封闭的(classes should be open for extension, closed for modification)。

也就是说对一个类只能做扩展,而不能被修改。

2.2.1、反例

enum class COLOR { RED, GREEN, BLUE };
enum class SIZE { SMALL, MEDIUM, LARGE };

struct Product {
    string  m_name;
    COLOR   m_color;
    SIZE    m_size;
};

using Items = vector<Product*>;
#define ALL(C)  begin(C), end(C)

struct ProductFilter {
    static Items by_color(Items items, const COLOR e_color) {
        Items result;
        for (auto &i : items)
            if (i->m_color == e_color)
                result.push_back(i);
        return result;
    }
    static Items by_size(Items items, const SIZE e_size) {
        Items result;
        for (auto &i : items)
            if (i->m_size == e_size)
                result.push_back(i);
        return result;
    }
    static Items by_size_and_color(Items items, const SIZE e_size, const COLOR e_color) {
        Items result;
        for (auto &i : items)
            if (i->m_size == e_size && i->m_color == e_color)
                result.push_back(i);
        return result;
    }
};

int main() {
    const Items all{
        new Product{"Apple", COLOR::GREEN, SIZE::SMALL},
        new Product{"Tree", COLOR::GREEN, SIZE::LARGE},
        new Product{"House", COLOR::BLUE, SIZE::LARGE},
    };

    for (auto &p : ProductFilter::by_color(all, COLOR::GREEN))
        cout << p->m_name << " is green\n";

    for (auto &p : ProductFilter::by_size_and_color(all, SIZE::LARGE, COLOR::GREEN))
        cout << p->m_name << " is green & large\n";

    return EXIT_SUCCESS;
}

一个产品(Product)可能有多个属性,然后我们需要过滤出特定属性的产品。

但按照上面代码的实现,存在下面几个问题:

  • 对于暴露出去的接口,如果要修改或新增属性,需要修改类和增加新的过滤函数
  • 需要频繁地修改类的实现

2.2.2、使用模版实现扩展

要实现 OCP 原则的方式,可以采用多态和模版。

template <typename T>
struct Specification {
    virtual ~Specification() = default;
    virtual bool is_satisfied(T *item) const = 0;
};

struct ColorSpecification : Specification<Product> {
    COLOR e_color;
    ColorSpecification(COLOR e_color) : e_color(e_color) {}
    bool is_satisfied(Product *item) const { return item->m_color == e_color; }
};

struct SizeSpecification : Specification<Product> {
    SIZE e_size;
    SizeSpecification(SIZE e_size) : e_size(e_size) {}
    bool is_satisfied(Product *item) const { return item->m_size == e_size; }
};

template <typename T>
struct Filter {
    virtual vector<T *> filter(vector<T *> items, const Specification<T> &spec) = 0;
};

struct BetterFilter : Filter<Product> {
    vector<Product *> filter(vector<Product *> items, const Specification<Product> &spec) {
        vector<Product *> result;
        for (auto &p : items)
            if (spec.is_satisfied(p))
                result.push_back(p);
        return result;
    }
};

// ------------------------------------------------------------------------------------------------
BetterFilter bf;
for (auto &x : bf.filter(all, ColorSpecification(COLOR::GREEN)))
    cout << x->m_name << " is green\n";

通过模版对外暴露接口,从而使得类可扩展,而不需要修改类的实现。

2.2.3、总结

使用 OCP 原则的方式,可以增强可扩展性、可维护性、灵活性。但实际上,一个类很难保持完全的封闭性,总会存在一些不可预见的、需要修改类实现的情况。对于可预见的,那么 OCP 原则是很不错的修改方式。

2.3、Liskov’s Substitution Principle (LSP)

LSP (里氏替换原则),主要思想是派生类对象可以在程序中代替其基类对象(Subtypes must be substitutable for their base types without altering the correctness of the program)。

以 C++ 举例来说明,就是指向基类对象的指针或引用可以被替换为派生类对象。

2.3.1、反例

struct Rectangle {
    Rectangle(const uint32_t width, const uint32_t height) : m_width{width}, m_height{height} {}

    uint32_t get_width() const { return m_width; }
    uint32_t get_height() const { return m_height; }

    virtual void set_width(const uint32_t width) { this->m_width = width; }
    virtual void set_height(const uint32_t height) { this->m_height = height; }

    uint32_t area() const { return m_width * m_height; }

protected:
    uint32_t m_width, m_height;
};

struct Square : Rectangle {
    Square(uint32_t size) : Rectangle(size, size) {}
    void set_width(const uint32_t width) override { this->m_width = m_height = width; }
    void set_height(const uint32_t height) override { this->m_height = m_width = height; }
};

void process(Rectangle &r) {
    uint32_t w = r.get_width();
    r.set_height(10);

    assert((w * 10) == r.area()); // Fails for Square <--------------------
}

在上面的代码案例中,正方形(Square)继承于矩形(Rectangle),在执行面积判断 process 函数时,就会出现替换错误。看似正确,实则矩形面积是以宽和高来定义的,而正方形是以长度来定义的,所以这样继承不是好的方式。

2.3.2、判断兼容

void process(Rectangle &r) {
    uint32_t w = r.get_width();
    r.set_height(10);

    if (dynamic_cast<Square *>(&r) != nullptr)
        assert((r.get_width() * r.get_width()) == r.area());
    else
        assert((w * 10) == r.area());
}

多加一层类型判断来进行兼容,也不是什么好的方式,实际上这并不是真正的可替换。

2.3.3、包含关系

void process(Rectangle &r) {
    uint32_t w = r.get_width();
    r.set_height(10);

    if (r.is_square())
        assert((r.get_width() * r.get_width()) == r.area());
    else
        assert((w * 10) == r.area());
}

因为矩形是包含正方形的,所以不需要创建正方形这个类,在有需要的地方做判断即可,但这也不是推荐的方式。

2.3.4、改进继承关系

struct Shape {
    virtual uint32_t area() const = 0;
};

struct Rectangle : Shape {
    Rectangle(const uint32_t width, const uint32_t height) : m_width{width}, m_height{height} {}

    uint32_t get_width() const { return m_width; }
    uint32_t get_height() const { return m_height; }

    virtual void set_width(const uint32_t width) { this->m_width = width; }
    virtual void set_height(const uint32_t height) { this->m_height = height; }

    uint32_t area() const override { return m_width * m_height; }

private:
    uint32_t m_width, m_height;
};

struct Square : Shape {
    Square(uint32_t size) : m_size(size) {}
    void set_size(const uint32_t size) { this->m_size = size; }
    uint32_t area() const override { return m_size * m_size; }

private:
    uint32_t m_size;
};

void process(Shape &s) {
    // Use polymorphic behaviour only i.e. area()
}

通过创建一个更加包容的基类,从而使得正方形类和矩形类都纳入其中,这样就能满足可替换性。

2.3.5、总结

LSP 原则可以达到很好的兼容性、类型安全、可维护性。在面向对象设计当中,仅仅描述“IS-A”(是什么)关系是不够的,更精确的应该是描述“IS-SUBSTITUTABLE-FOR”(可被替换为)关系。

2.4、Interface Segregation Principle (ISP)

ISP (接口隔离原则),主要思想是客户不应被迫使用对其而言无用的方法或功能(Clients should not be forced to depend on interfaces that they do not use)。

也就是说,设计抽象接口应该只完成用户需要的功能,把非常庞大臃肿的接口划分成更小的和更具体的,这样客户只需要知道他们感兴趣的方法,也更方便解耦和重构。

2.4.1、反例

struct Document;

struct IMachine {
    virtual void print(Document &doc) = 0;
    virtual void fax(Document &doc) = 0;
    virtual void scan(Document &doc) = 0;
};

struct MultiFunctionPrinter : IMachine {      // OK
    void print(Document &doc) override { }
    void fax(Document &doc) override { }
    void scan(Document &doc) override { }
};

struct Scanner : IMachine {                   // Not OK
    void print(Document &doc) override { /* Blank */ }
    void fax(Document &doc) override { /* Blank */ }
    void scan(Document &doc) override {  
        // Do scanning ...
    }
};

在基类机器(IMachine)要对文档进行操作当中,暴露了三个接口,打印(print)、传真(fax)、扫描(scan),对于打印机而言是正常的,但对于扫描仪而言,它并没有打印和传真的功能,被迫把这两个接口的实现为空。

2.4.2、接口分离

/* -------------------------------- Interfaces ----------------------------- */
struct IPrinter {
    virtual void print(Document &doc) = 0;
};

struct IScanner {
    virtual void scan(Document &doc) = 0;
};
/* ------------------------------------------------------------------------ */

struct Printer : IPrinter {
    void print(Document &doc) override;
};

struct Scanner : IScanner {
    void scan(Document &doc) override;
};

struct IMachine : IPrinter, IScanner { };

struct Machine : IMachine {
    IPrinter&   m_printer;
    IScanner&   m_scanner;

    Machine(IPrinter &p, IScanner &s) : printer{p}, scanner{s} { }

    void print(Document &doc) override { printer.print(doc); }
    void scan(Document &doc) override { scanner.scan(doc); }
};

和单一功能原则(SRP)比较类似,通过分离接口,提供客户感兴趣的接口。

2.4.3、总结

ISP 原则可以使得编译更快(因为如果接口签名改变,所有子类都要重编)、可复用的、可维护的。所以在设计接口类时,要设想这个类中的所有方法是否真的需要用到。

2.5、Dependency Inversion Principle (DIP)

DIP (依赖反转原则),主要思想是:

  • 高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口(High-level modules should not depend on low-level modules. Both should depend on abstractions)
  • 抽象接口不应该依赖于具体实现,而具体实现则应该依赖于抽象接口(Abstractions should not depend on details. Details should depend on abstractions)

高层次模块是更加抽象以及包含更多的复杂逻辑,低层次模块描述更具体的实现以及是独立的实现细节的部分。

2.5.1、反例

enum class Relationship { parent, child, sibling };

struct Person {
    string      m_name;
};

struct Relationships {      // Low-level <<<<<<<<<<<<-------------------------
    vector<tuple<Person, Relationship, Person>>     m_relations;

    void add_parent_and_child(const Person &parent, const Person &child) {
        m_relations.push_back({parent, Relationship::parent, child});
        m_relations.push_back({child, Relationship::child, parent});
    }
};

struct Research {           // High-level  <<<<<<<<<<<<------------------------
    Research(const Relationships &relationships) {
        for (auto &&[first, rel, second] : relationships.m_relations) {// Need C++17 here
            if (first.m_name == "John" && rel == Relationship::parent)
                cout << "John has a child called " << second.m_name << endl;
        }
    }
};

在上面的代码案例中,关系链调查,如果 Relationships 类当中的变量改变类型或者名字的话,将会导致高层次模块 Research 类出问题,而这两个类之间还存在很多的关联。

2.5.2、依赖反转

struct RelationshipBrowser {
    virtual vector<Person> find_all_children_of(const string &name) = 0;
};

struct Relationships : RelationshipBrowser {     // Low-level <<<<<<<<<<<<<<<------------------------
    vector<tuple<Person, Relationship, Person>>     m_relations;

    void add_parent_and_child(const Person &parent, const Person &child) {
        m_relations.push_back({parent, Relationship::parent, child});
        m_relations.push_back({child, Relationship::child, parent});
    }

    vector<Person> find_all_children_of(const string &name) {
        vector<Person> result;
        for (auto &&[first, rel, second] : m_relations) {
            if (first.name == name && rel == Relationship::parent) {
                result.push_back(second);
            }
        }
        return result;
    }
};

struct Research {                                // High-level <<<<<<<<<<<<<<<----------------------
    Research(RelationshipBrowser &browser) {
        for (auto &child : browser.find_all_children_of("John")) {
            cout << "John has a child called " << child.name << endl;
        }
};

我们可以创建一个抽象接口类,来把高层次模块和低层次模块连接到一起。这样其中的一些修改就不会导致另一个类出问题。

2.5.3、总结

如果转换成 DIP 原则比较困难的话,就应该先设计抽象接口类,然后实现基于抽象的高层次模块,而不能提前感知到低层次模块的实现。

DIP 原则可以带来复用性、可维护性。不要尝试混用各个类对象,应该首先使用抽象。

参考

What Is Design Pattern?:http://www.vishalchovatiya.com/what-is-design-pattern/

Single Responsibility Principle in C++:http://www.vishalchovatiya.com/single-responsibility-principle-in-cpp-solid-as-a-rock/

单一功能原则:https://zh.wikipedia.org/zh-cn/%E5%8D%95%E4%B8%80%E5%8A%9F%E8%83%BD%E5%8E%9F%E5%88%99

Open Closed Principle in C++:http://www.vishalchovatiya.com/open-closed-principle-in-cpp-solid-as-a-rock/

开闭原则:https://zh.wikipedia.org/zh-cn/%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99

Liskov’s Substitution Principle in C++:http://www.vishalchovatiya.com/liskovs-substitution-principle-in-cpp-solid-as-a-rock/

里氏替换原则:https://zh.wikipedia.org/zh-cn/%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99

Interface Segregation Principle in C++:http://www.vishalchovatiya.com/interface-segregation-principle-in-cpp-solid-as-a-rock/

接口隔离原则:https://zh.wikipedia.org/zh-cn/%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99

Dependency Inversion Principle in C++:http://www.vishalchovatiya.com/dependency-inversion-principle-in-cpp-solid-as-a-rock/

依赖反转原则:https://zh.wikipedia.org/zh-cn/

第九十三篇:代码重构与设计原则(SOLID):编写可扩展、可维护的代码 本文探讨了软件设计中SOLID原则的应用,重点介绍了单一职责原则(SRP)。SRP强调一个类只应承担一个职责,避免"上帝类"问题。文章通过Python示例展示了违反SRP的UserManager类(集验证、加密、持久化等职责于一身)与遵循SRP的优化方案(将职责分解为EmailValidator、PasswordHasher等独立组件)。这种职责分离的设计提高了代码的可维护性和扩展性,使每个变更只需修改特定模块而非整个系统。 阅读详情

相关推荐

利用netns做自环Iperf测试

netns可以让一台机器上模拟多个网络设备,是网络虚拟化的重要组成,将不同类型的网络应用隔离。一个net namespace有自己独立的路由表,iptables策略,设备管理。本文利用netns模拟网络来实现单机上网卡自环上的iperf测试或其他网络测试。

weixin_42414349的博客 3370

面向对象的五大基本设计原则:SOLID

什么是设计原则 ⾯向对象过程中,前辈⼤咖们推荐的⼀些指导性原则,遵循这些原则可以让你的设计更有竞争力。 一、单⼀职责原则(SRP:Single Responsibility Principle) 背景: 单⼀职责原则,SRP⼜称单⼀功能原则,⾯向对象五个基本原则(SOLID)之⼀。它规定⼀个类应 该只有⼀个发⽣变化的原因。该原则由罗伯特·C·⻢丁(Robert C. Martin)于《敏捷软件开发:原 则、模式和实践》⼀书中给出的。 ------------------------.

Gyp郭小帅的博客 754

数字IC面试核心:从MUX基础到Glitch-Free时钟切换电路深度剖析

本文深入剖析数字IC设计中的MUX基础原理及其在Glitch-Free时钟切换电路中的应用。从二选一MUX的门级实现到时钟切换中的毛刺问题,详细讲解了同步切换机制和工程优化技巧,帮助工程师掌握高速时钟电路设计的核心要点。

weixin_42629815的博客 324

架构师之路——面向对象的SOLID原则

面向对象的SOLID设计原则

weixin_61492871的博客 906

USRP B210 运行gnuradio时 FPGA固件版本冲突错误解决方法

事情起源于昨天拿到USRP后开始调试,结果整了一个下午都没解决这个问题。 昨天晚上自己思考了一下,觉得还是版本问题。 首先,uhd_find_devices和uhd_usrp_probe均可以正常运行,没有报错,固件正常加载,序列号也可看到。 teray@teray-X550JK:~$ uhd_find_devices [INFO] [UHD] linux; GNU C++ version 7.5...

斯哈研究所 4243

ARM Memory Compiler实战指南:从参数配置到GDSII生成的全流程解析

本文详细解析了ARM Memory Compiler在SRAM设计中的全流程应用,从基础参数配置到GDSII文件生成。涵盖SRAM类型选择、核心参数配置策略、高级优化技巧及TSMC 28nm工艺下的实战案例,帮助IC设计工程师高效实现存储器模块的优化设计。

game4的博客 417

面向对象设计的五大原则(SOLID 原则)

面向对象设计的五大原则(SOLID 原则)是指导我们设计可维护、灵活且易扩展的面向对象系统的核心准则。这些原则帮助开发者避免常见的设计陷阱,使代码更具可读性和可维护性。

alittlefish1的博客 1840

Vue3 - 超详细最新 wangEditor V5 富文本编辑器安装引入及使用教程,提供工具栏配置、基础富文本功能、API使用示例教程等(新手小白快速引入并植入到项目中)

vue3,wangEditorv5富文本编辑器,wangEditorv5官方文档,vue3最新安装wangEditorv5富文本详细使用教程,vue3使用wangEditorv5编辑器示例代码,vue3网站网页安装植入富文本编辑器教程,vue3wangEditor使用api,vue3安装富文本控制台出现报错如何解决,vue3wangEditor-v5工具栏配置,vue3中使用富文本编译器wangEditor5的方法,wangeditor5在vue3中的全使用过程,vue3超详细最新wangedi

🏆 前端领域优质创作者 4253

面向对象设计模式-SOLID原则

高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。这意味着接口的设计应该小而专注。子类型必须能替换其基类型。

weixin_44496853的博客 948

Python操作WPS文档

在Python中,我们可以使用第三方库来操作WPS文档,实现自动化的文档处理。本文将介绍如何使用Python来打开、读取、修改和保存WPS文档的内容。库,我们可以打开、读取、修改和保存WPS文档的内容。你可以根据自己的需求进一步扩展和优化这些代码,实现更复杂的文档处理功能。安装完成后,我们就可以开始使用它来操作WPS文档了。方法将修改后的文档保存到指定的路径。方法将修改后的文档保存到指定的路径。在上面的代码中,我们通过修改段落的。属性,可以改变段落的文本内容。完成对文档的修改后,我们可以使用。

2301_79366177的博客 5615

Linux7 挂载 nfs 远程目录

每天一个 DBA 小知识,助你更进一步!

LuciferLiu_DBA 1万+

从C++示例理解开闭原则

可以看出当我们有新的需求时,必须要对 ProductFilter 类进行修改,并没有遵循开闭原则,所以我们希望重新设计使这个程序满足开闭原则,重构主要用到 template 模版编程。这里的类型 T 可以由我们自由地指定,我们可以指定为类型 Product 也可以指定为其他类型,这就意味着,这个规范将不再局限于 Product,我们可以在任何其他类型中使用它。开闭原则要求我们在编写代码时,尽量不去修改原先的代码,当出现新的业务需求时,应该通过增加新代码的形式扩展业务而不是对原代码进行修改。

CodeSingerAlex的博客 810

实战复盘:纷玩岛(Livelab)候补订单微信支付协议的逆向与复现

通过本次对纷玩岛候补支付接口的分析,我们实现了一个脱离 App UI 的轻量级支付发起器。这不仅验证了其API的设计逻辑(Standby -> PrePayInfo 分层设计),也为后续的自动化监控或辅助抢票工具提供了支付环节的技术验证。技术本无罪,关键在于如何使用。理解这些底层协议,有助于我们写出更健壮的代码,也能在遇到线上支付问题时快速定位是业务层(API)问题还是通道层(微信)问题。

猫敷雪 801

三、1如何运用设计原则之SOLID原则写出高质量代码?

对输入,输出,异常的约定;也就是添加一个新的功能时,应该在已有的代码基础是扩展新的模块,类,方法等,而不是修改已有代码(模块,类,方法等),所以说代码的扩展性是重点。是一种编程技巧,不通过new()的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数,构造参数等方式传递(或注入)给类使用,这样提高了代码的扩展性。我们通过依赖注入框架提供的扩展点,简单配置所需要的类,以及类与类之间依赖关系,就可以实现由框架来自动创建对象,管理对象是生命周期,依赖注入等原本需要程序员来做的事情。

FUSIPING的博客 423

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

结合SOLID设计原则,浅谈如何提升前端代码质量

前言:什么是SOLID设计原则, 为什么使用它在程序设计领域, SOLID(S: 单一功能、O: 开闭原则、L: 里氏替换、I: 接口隔离、D: 依赖反转),指代了面向对象设计的五个基本原则。当这些原则被一起应用时,可以让软件更加健壮和稳定。我为什么要使用它,最开始是因为对产品经理需求的恐惧,这可能是很多前端都面临的一个问题,就是需求变动非常频繁。我现在做的是后台系统,我...

React_Community的博客 764

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

一文漫谈SOLID设计原则:从能跑就行到能改十年的代码进化之路

在软件工程中,面向对象编程不仅仅是封装、继承与多态的语法组合,更是一套关于代码组织与演进的设计哲学。当项目规模扩大,需求频繁变更,代码的可维护性便成为核心挑战。SOLID设计原则正是为此而生,它由单一职责、开闭、里氏替换、接口隔离与依赖倒置五项原则构成,分别从类的职责、扩展方式、继承契约、接口边界与依赖方向等维度,指导开发者构建低耦合、高内聚的系统。遵循这些原则,能够有效降低重构风险,提升代码复用性,使系统在面对新功能时更倾向于扩展而非修改。无论是模块拆分、服务接口设计,还是日常的代码审查,SOLID原则都

weixin_32430941的博客 319

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

solid 设计原则 php,PHP代码简洁之道——SOLID原则

SOLID 是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则S: 单一职责原则 (SRP)O: 开闭原则 (OCP)L: 里氏替换原则 (LSP)I: 接口隔离原则 (ISP)D: 依赖反转原则 (DIP)单一职责原则 Single Responsibility Principle (SRP)"修改一个类应该只为...

weixin_31526891的博客 271

SOLID 设计原则 In C# 代码实现

[S] Single Responsibility Principle (单一职责原则) 认为一个对象应该仅只有一个单一的职责 namespace SingleResponsibilityPrinciple { class DataAccess { void InsertData() { Console...

weixin_30655569的博客 114

面向对象设计原则:SOLID与代码可维护性实践

面向对象设计原则是软件工程中管理代码复杂度的核心方法论,其本质是通过约束对象交互方式实现高内聚低耦合。SOLID原则作为经典范式,包含单一职责、开闭原则等五大维度,能有效解决代码臃肿、扩展困难等工程问题。在电商系统、支付平台等实际场景中,合理运用这些原则可使代码维护成本降低80%。特别是结合策略模式、建造者模式等设计模式时,既能保证系统扩展性(热词1),又能提升团队协作效率(热词2)。掌握这些原则对实现领域驱动设计、微服务架构等现代软件开发至关重要。

weixin_30536861的博客 252

高效Swift类设计原则(SOLID应用篇):打造企业级代码架构的黄金法则

掌握Swift类定义的高效设计方法,解决企业级架构可维护性难题。结合SOLID原则,详解适用大型项目的类设计技巧,提升代码复用与可扩展性。遵循这些黄金法则,让Swift类定义更清晰稳健,值得收藏。

DevPath的博客 727

代码设计原则与OWASP安全最佳实践:从SOLID到防御性编程的融合落地

在软件开发中,代码设计原则与安全实践并非割裂的独立领域,而是共同决定系统可维护性与安全性的两面。SOLID、DRY、KISS、YAGNI 这四组经典原则,分别从结构边界、逻辑重复、方案复杂度和功能范围四个维度规范代码设计,而 OWASP 提供的 ASVS 标准与 Top 10 漏洞清单则构建了从威胁建模到安全编码的完整基线。当业务系统面临频繁迭代与安全审计的双重压力时,设计原则的缺失会直接放大攻击面:过度设计制造多余入口,重复逻辑导致修复遗漏,职责混乱掩盖数据流向。通过将设计原则作为安全评审的检查项,并以

weixin_29323493的博客 250

SOLID原则实战:用五大设计原则根治代码腐烂

面向对象设计中的耦合度控制是软件可维护性的核心问题。SOLID原则通过单一职责、开闭、里氏替换、接口隔离和依赖倒置五个维度,系统性地降低模块间依赖,提升代码可扩展性与可测试性。在业务代码迭代、模块重构和代码评审等场景中,这些原则能有效隔离变化、减少回归风险。本文结合真实踩坑经验,逐条拆解SOLID原则的判断标准与落地方法,并给出可复用的代码示例与评审自检表。

weixin_32430941的博客 183

SOLID设计原则深度解析:面向对象架构与代码重构实战指南

面向对象编程中,类与模块的扩展性往往决定软件架构的寿命。设计模式与架构实践反复验证,当需求变更频繁时,单纯依赖语法特性难以应对复杂性增长。SOLID作为一组经典设计原则,从单一职责、开闭、里氏替换、接口隔离、依赖倒置五个维度,为代码评审和重构提供了清晰的检查清单。它帮助开发者识别变化方向、降低耦合,提升可测试性与可维护性,广泛应用于Java、C#、Python、TypeScript等主流OOP项目以及嵌入式开发中。在实际工程里,将SOLID落地到订单、支付、报表等模块,能有效控制改动半径,减少跨文件连带修改

weixin_30444111的博客 205

SOLID 设计原则,代码示例(show me the code)

认识 SOLID 原则 无论是软件系统设计,还是代码实现,遵循有效和明确的设计原则,都利于系统软件灵活可靠,安全快速的落地,更重要的是能灵活地应对需求,简化系统扩展和维护,避免无效的加班。本文主要讨论面向对象软件开发中最流行的设计原则- SOLID,它是五个设计原则为了方便记忆而组成的首字母缩写: 单一职责原则 开放/封闭原则 里式替换原则 接口隔离原则 依赖倒置原则 S:单一职责原则 (SRP) 基本概念 单一职责原则 (SRP) 英文全称为 Single Responsibi..

肖邦的夜曲的专栏 1070
上一篇: C++ 析构函数的坑
下一篇: C++ 异常是如何实现的
流左沙
博客等级 码龄11年 46粉丝 55原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值