设计模型 -七大原则

设计模式

设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案

关于面向对象:

  • 向下:深入理解三大面向对象机制
    • 封装,隐藏内部实现
    • 继承,复用现有代码
    • 多态,改写对象行为
  • 向上:深刻把握面向对象机制所带来的抽象意义,理解如何使用这些机制来表达现实世界,掌握什么是“好的面向对象设计

七大原则

  1. 开闭原则
  2. 依赖倒转(倒置)原则
  3. 单一职责原则
  4. 接口隔离原则
  5. 里氏替换原则
  6. 迪米特法则
  7. 合成复用原则

2.2.1 开闭原则(Open-Closed Principle, OCP)

  • 概念
    • 类模块应该是可扩展的,但是不可修改。
    • 对扩展开放,对更改关闭。
  • 方法:
    • 可通过虚函数来扩展订单类型。而无需修改现有的

2.2.2 单一职责(Simple Responsibility Pinciple,SRP)

  • 概念
    • 每个应该实现单一职责,否则就应该把类拆分,便于后期的维护
    • 不要存在多余一个导致类变更的原因。一个类应该应该只负责一项职责。
    • ​​​​​​由于第一点要求可能导致类的数量变得多,所以尽量通过组合而不是继承来实现功能,使得类的数量不是太多
  • 方法:
    • 为了遵循单一职责,我们应该将文件操作、日志记录、压缩操作分为独立的类来使用,甚至我们还可以进一步来优化,设计一个抽象类编译更好的代码扩展和替换。

2.2.3 依赖倒置原则(Dependence Inversion Principle,DIP)

  • 高层模块(稳定)不应该依赖于底层模块(变化),二者都应该依赖于抽象(稳定)
  • 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定).

2.2.4 里氏替换原则(Liskov Substitution Principle,LSP)

    • 子类必须能够替换它们的基类(IS-A)。
    • 子类必须保持和父类接口的一致性
    • 子类可以扩展父类的功能
    • 子类不应该引入新的错误或异常

通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。【尽量不用重写父类的方法】

2.2.5 接口隔离原则(Interface Segregation Principle,ISP)

  • 使用多个专门的接口,而不使用单一的总接口,不应该强迫客户程序依赖它们不用的方法
  • 接口尽量细化,同时接口中的方法尽量少并且完备。
  • 在实际中使用,根据业务职业将抽象类接口分为多个接口,按照接口职责来进行区分,因为抽象类中,有很多纯虚函数,所以在继承他的时候,就必须要把所有的纯虚函数都给实现,这样就导致冗余,所以在实现的时候,因为把需要的部分摘取出来,重新成立一个类,或者把那个总类单独抽取出来,一开始就分出来,

(注:这里和"单一职责"是有区别的,单一职责强调类的职责单一,站在业务逻辑的角度,这里强调的是接口,要求接口的方法尽可能的少而完备)

      

2.2.6 迪米特法则(Law of Demeter LoD)

迪米特原则(Law of Demeter LoD)是指一个对象应该对其他对象保持最少的了解,又叫最少知道原则(Least Knowledge Principle,LKP),尽量降低类与类之间的耦合。迪米特原则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类

2.2.7 合成复用原则(Composite Reuse Principle,CRP

合成复用原则(Composite Reuse Principle,CRP)是面向对象设计中的一个重要原则,它强调在系统设计中应该优先使用组合(Composition)而不是继承(Inheritance)来实现代码的复用和组织。这个原则的核心思想是:要尽量通过将现有的类组合起来创建新的功能,而不是通过继承已有的类来实现复用。

继承的方法:

比如现在要画一个带颜色的形状,比如颜色有红绿蓝,形状有正方形、长方形、圆形。如果是继承的方法,那就要分别定义9个类,比如红圆、绿圆、蓝圆,等等九个类,再分别定义他们的方法

class Shape {
public:
    virtual void draw() = 0;
};

class RedCircle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing Red Circle" << std::endl;
    }
};

组合的方法:

只需要预先定义六个类,shape类中有三个,正方形、长方形、圆形类,color类中有三个,红类、绿类、蓝类。

然后我们在实现的时候自己组合即可

class Color {
public:
    virtual void fill() = 0;
};

class Red : public Color {
public:
    void fill() override {
        std::cout << "Filling with Red" << std::endl;
    }
};

class Shape {
public:
    Shape(Color* color) : color(color) {}

    virtual void draw() = 0;

protected:
    Color* color;
};

class Circle : public Shape {
public:
    Circle(Color* color) : Shape(color) {}

    void draw() override {
        std::cout << "Drawing Circle with ";
        color->fill();
    }
};


    Color* red = new Red();

    Shape* redCircle = new Circle(red);

在类多的情况下,组合很好。

  • 总结
    • 我们发现合成复用原则里氏替换原则好像是冲突的。其实并不是,他们是相辅相成的面向对象设计原则。合成复用原则(CRP)强调通过组合已有的类来实现复用,而不是通过继承来实现。它鼓励将对象组合在一起以创建新的功能,以降低类之间的耦合度,提高灵活性和可维护性。

里氏替换原则(LSP)强调子类应该能够替换其基类而不影响程序的正确性。LSP指出,

派生类应该保持与基类一致的行为,遵守基类的契约和约定,以确保多态性的正确性。

  • 当我们需要降低代码耦合性组合复杂的功能设计组件替换的时候可以选择CRP
  • 当我们需要提供代码重用性提高代码扩展性提高代码稳定性的时候可以选择LSP。
  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值