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等独立组件)。这种职责分离的设计提高了代码的可维护性和扩展性,使每个变更只需修改特定模块而非整个系统。 阅读详情

相关推荐

软件测试工程师笔试题

这里写目录标题全套软件测试面试笔试题(附答案)二、选折三、添空四、简答(资料是搜集整理的,感谢前辈的解题)无1.区别阶段评审的与同行评审2.什么是软件测试3. 简述集成测试的过程4 怎么做好文档测试5 白盒测试有几种方法6 系统测试计划是否需要同行审批,为什么7Alpha 测试与 beta 的区别8 比较负载测试,容量测试和强度测试的区别。性能测试从使用方便的角度来说,9 测试结束的标准是什么?10 描述软件测试活动的生命周期?11 软件的缺陷等级应如何划分? 软件测试工程师笔试题(附答案) 全套软件测试面

m0_46446002的博客 2549

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

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

Gyp郭小帅的博客 754

瑞萨RZN2L工业以太网开发避坑指南:EtherCAT从入门到通信调试全流程

本文详细解析了瑞萨RZN2L MPU在工业以太网开发中的EtherCAT从站配置与通信优化全流程。通过硬件设计关键点、协议栈选型、PDO映射策略及DC同步精度优化等实战技巧,帮助开发者快速搭建高效通信框架并解决调试中的常见问题,特别适合工业自动化领域的实时通信需求。

aitie1479的博客 461

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

面向对象的SOLID设计原则

weixin_61492871的博客 906

【HCIE】FRR+BFD+OSPF与BGP联动

FRR+BFD+OSPF与BGP联动

Wenrs的博客 1996

基因树构建全流程:从OrthoFinder到iTOL的保姆级教程(附兰科植物案例)

本文提供了一份从OrthoFinder到iTOL的基因树构建全流程保姆级教程。详细解析了利用OrthoFinder构建物种树、IQ-TREE构建无根基因树、Notung进行树调和生根,以及最终在iTOL中实现专业可视化的每一步操作与实战经验,并以兰科植物NB-ARC基因家族为例进行演示,帮助研究者系统掌握基因树分析方法。

tequila的博客 523

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

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

alittlefish1的博客 1840

走马观碑组智能车竞赛:目标板识别算法优化与实战技巧(基于OpenCV)

本文针对智能车竞赛走马观碑组别的核心挑战,深入探讨了基于OpenCV的目标板识别算法优化与实战技巧。文章系统分析了PVC赛道环境下的光照、运动模糊等干扰因素,详细拆解了从红色矩形定位、透视校正到特征提取与分类的完整流程,并提供了工程优化、速度提升及现场调试的实用策略,旨在帮助参赛队伍构建一套在高速运动中既准又快的鲁棒识别系统。

life6的博客 732

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

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

weixin_44496853的博客 948

在Ubuntu 20.04上,用EtherCAT Igh 1.6.2驱动高创BD3E伺服电机(附完整C代码)

本文详细介绍了在Ubuntu 20.04实时内核环境下,使用EtherCAT Igh 1.6.2主站驱动高创BD3E伺服电机的完整实现方案。从实时系统配置、伺服电机PDO映射到精确控制线程设计,提供了完整的C代码样例和实际项目中的调试技巧,帮助开发者实现工业自动化中的高精度运动控制。

weixin_30772105的博客 110

星网锐捷语音网关密码重置全攻略:两种高效恢复出厂设置方法详解

本文详细解析了星网锐捷语音网关密码重置的两种高效方法,包括通过eth1通用口和eth0管理口的操作步骤。针对不同型号设备,提供硬件连接、Web控制台登录及CRT工具使用的具体指南,帮助用户快速恢复出厂设置并重建语音环境配置。

weixin_28698059的博客 528

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

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

CodeSingerAlex的博客 810

AgentScope 实战训练营-A2UI的完整实现:从概念到部署全流程

本文详细介绍了如何在AgentScope框架中实现Google的A2UI(Agent-to-Agent UI)协议,构建一个能生成可交互UI的智能体应用。文章涵盖了从环境准备、架构设计、核心代码实现到测试部署的完整流程,包括A2UI协议解析、技能系统、客户端实现、通信机制等核心技术点,适合AI Agent和前端开发人员学习参考。

program哲学 201

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

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

FUSIPING的博客 423

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

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

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

React_Community的博客 764

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

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

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

weixin_32430941的博客 319

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

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、付费专栏及课程。

余额充值