- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
找出应用中需要经常变化的部分,把他们独立出来,改变这部分代码不影响其他部分。 这几乎是每个设计模式背后的精神所在,即系统中某部分的改变不影响其他部分.
针对接口编程,关键在于 多态 。变量/成员/形参的声明应该是抽象类/接口类/父类,即所有的代码操作的都是父类/接口类/抽象类(如 Animal),只会在一处会涉及到具体类(如 Cat 或 Dog),那就是在用 new 实例化具体子类对象时,而这部分代码最好也用工厂封装起来,这样甚至可以在运行时动态实例化不同的子类对象.
针对实现编程 👎 | 针对接口编程 👍 | 针对接口编程 + 工厂 👍👍 |
---|---|---|
Dog d = new Dog(); d.bark(); |
Animal a = new Dog(); a.makeSound(); |
Animal a = getAnimal(); a.makeSound(); |
继承和组合都可以实现代码复用,但组合比继承更灵活,可运行时改变行为/属性。例如下面的游戏战车,采用组合可以在运行时动态地通过 setWeapon() 来切换武器,而继承是在编译时静态决定子类行为,则没有这种灵活性.
继承(is-a) 👎 | 组合(has-a) 👍 |
---|---|
例如观察者模式使得观察者(Listener)和被观察者(Subject)之间是松耦合的。被观察者(Subject)不知道观察者的细节,只知道观察者实现了 Listener 接口(如 update() ),只要他们之间的接口不变,就可以自由地改变一方而不影响另一方.
最少知识原则(LKP, Least Knowledge Principle)也被称为迪米特法则(Law of Demeter)。其目的是减少对象之间的交互和类之间的依赖,不要让太多的类耦合在一起,避免修改一部分影响到另一部分.
为了避免依赖过多的类,在 Foo 类的方法 func(Bar bar) 中只应该调用:
Foo
类自身的方法/成员函数 Foo
类成员的方法 bar
的方法 func()
中创建的对象的方法 应避免调用由另一个方法返回的对象的方法,即避免像下面这样连续的函数调用:
// 👎 依赖 Station、Thermometer 类
float getTemp() {
return station.getThermometer().getTemperature();
}
// 👍 只依赖 Station 类
float getTemp() {
return station.getTemperature();
}
外观模式是该原则的体现。Facade 封装了复杂的子系统,提供了统1、简单的高层接口, Client 只和 Facade 进行交互,避免了 Client 和子系统的紧耦合.
缺点:需要额外的包装类,增加复杂度,降低运行时性能.
允许低层组件将自己挂钩(hook)到系统上,但是高层组件决定什么时候和怎样使用这些低层组件(即高层组件对待低层组件的方式是:Don't call me, I'll call you)。一个典型例子是模版方法模式:
class Drink {
public:
void makeDrink() final
{
boilWater();
brew();
pourInCup();
addCondiments();
}
void boilWater() {...}
virtual void brew() = 0;
void pourInCup() {...}
virtual void addCondiments() = 0;
};
高层组件 Drink 的 makeDrink() 方法控制着饮料制作方法流程。低层组件 Tea/Coffee 通过 override brew()/addCondiments() 方法可以将自己 hook 到系统上,从而改变最终的行为。高层组件控制着何时、如何让低层组件参与,低层组件不可以直接调用高层组件。客人只依赖 Drink 类,而不依赖具体的 Tea/Coffee 类.
此外,工厂方法、观察者等模式也遵循了该原则:如工厂方法子类决定如何创建具体对象、低层的 Listener 把自己添加到高层被观察者的 Listener 列表中等。特别地,标准库中的很多算法也是该原则的体现:例如用标准库 sort 算法对自定义类的对象进行排序,需要传入一个可调用对象(比较函数/lambda).
思考:和依赖倒置原则的关系?
这是最著名的 5 个设计原则,在 《整洁架构之道》的第三部分的学习笔记 中再次详细介绍这 5 个原则.
Just because you can doen't mean you should. 。
类应该只有一个改变的理由。这背后的原因是每次修改代码可能产生潜在的错误。一个类只做一件事的时候,更容易实现高内聚;反之,如果一个类支持多个不相关的功能时,通常是低内聚的。当项目中经常由于不同的原因修改一个类的时候,或者负责不同业务的两个团队经常需要修改同一个文件,则是时候考虑单一职责原则了.
类应该对扩展开放,对修改关闭。扩展新功能只需 新增 代码,而不需要 修改 现有代码,减少 code review 的工作量及意外引入 bug 的可能性 。
需要父类的地方都可以用子类替代。其背后的目的是希望组件之间可以任意替换.
一个接口中有几十个方法,但客户 A。可能只需要其中的几个方法,而另一个客户 B 可能需要另外几个方法。臃肿的接口使得两个客户之间产生耦合,为客户 A 修改的某些方法也会影响到客户 B,即使客户 B 并没有用到这些方法.
依赖倒置原则的另一种表达方式是: 要依赖抽象,不要依赖具体类 。和“针对接口编程, 不针对实现编程”很相似,但这里更强调抽象。高层策略性代码不应该依赖低层实现细节代码,两者都应该依赖抽象。抽象也可以看作是高层策略的一部分,即低层细节实现应该依赖高层。控制流方向往往都是从高层到低层,而依赖倒置,是将源码的依赖关系反转,在源码级别上使得低层代码依赖高层策略。这一点对于软件架构来说尤为重要, 《架构整洁之道》 的第三部分深入地讨论了这一点.
Don't Repeat Yourself 不要重复。重复是一切邪恶的根源。许多原则、最佳实践都是为了消除重复.
Keep It Simple and Stupid 保持简单。不要本末倒置,简单的事情简单做!不要过度设计,不要把简单的事情搞复杂! 。
最后此篇关于面向对象设计原则总结:SOLID/LKP/DRY/KISS…的文章就讲到这里了,如果你想了解更多关于面向对象设计原则总结:SOLID/LKP/DRY/KISS…的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
目录 封装变化 针对接口编程,不针对实现编程 多用组合(has-a),少用继承(is-a) 为交互对象之间的松耦合设计而努力 最少知识原则 LKP / 迪
我的任务是开发一个 Java 库,用于与 CMMO-ST-C5-1-LKP Festo Controller 进行通信。我已阅读 Controller 文档,它提供了 MODBUS TCP/IP 通信
我正在尝试使用 Qt/C++ 通过 modbus 与电机 Controller 进行通信。 我使用主要从 Qt SerialBus adueditor 示例中获取的代码连接到它: void S
我是一名优秀的程序员,十分优秀!