侧边栏壁纸
  • 累计撰写 98 篇文章
  • 累计创建 20 个标签
  • 累计收到 3 条评论

设计模式七大原则

林贤钦
2020-04-26 / 0 评论 / 9 点赞 / 646 阅读 / 0 字
温馨提示:
本文最后更新于 2020-05-09,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

设计模式七大原则

1、设计模式的目的

编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性 等多方面的挑战,设计模式是为了让程序(软件),具有更好

  1. 代码重用性

相同功能的代码,不用多次编写

  1. 可读性

编程规范性, 便于其他程序员的阅读和理解

  1. 可扩展性

当需要增加新的功能时,非常的方便,称为可维护

  1. 可靠性

当我们增加新的功能后,对原来的功能没有影响

  1. 使程序呈现高内聚,低耦合的特性

分享金句

  • 设计模式包含了面向对象的精髓,“懂了设计模式,你就懂了面向对象分析和设计(OOA/D)的精要”
  • Scott Mayers 在其巨著《Effective C++》就曾经说过:C老手和 C新手的区别就是前者手背上有很多伤疤

2、设计模式七大原则

设计模式原则,其实就是程序员在编程时,应当遵守的原则,也是各种设计模式的基础(即:设计模式为什么这样设计的依据)

设计模式常用的七大原则有:

  •  单一职责原则
  •  接口隔离原则
  •  依赖倒转(倒置)原则
  •  里氏替换原则
  •  开闭原则
  •  迪米特法则
  •  合成复用原则

2.1 单一职责原则(Single Responsibility Principle)

目的

降低代码复杂度、系统解耦合、提高可读性

含义

对于一个类,只有一个引起该类变化的原因;该类的职责是唯一的,且这个职责是唯一引起其他类变化的原因。

解决

对类来说的,即一个类应该只负责一项职责。如类 A 负责两个不同职责:职责 1,职责 2。当职责 1 需求变更而改变 A 时,可能造成职责 2 执行错误,所以需要将类 A 的粒度分解为 A1,A2

实例

电线类Wire为居民供电,电压为220v;但是新的需求增加,电线也输送高压电,电压为200kv,原有电线类可以增加方法实现扩充,这就违背了单一职责原则。可以提供基类,创建两个派生类,居民供电线、高压输电线。

单一职责原则注意事项和细节

  • 1、降低类的复杂度,一个类只负责一项职责;
  • 2、提高类的可读性,可维护性;
  • 3、降低变更引起的风险;
  • 4、通常情况下,应当遵守单一职责原则, 只有逻辑足够简单,才可以在方法级违反单一职责原则。

2.2 接口隔离原则(Interface Segregation Principle)

目的

避免接口过于臃肿

含义

客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上

解决

适度细化接口,将臃肿的接口拆分为独立的几个接口。

实例

考试接口,包含考语数外、理化生、政史地等方法。学生类,实现考试接口,参加考试。文科生类、理科生类派生自学生类,实现考试接口时,就都需要实现一些自己不需要的方法(因为文科生不考理化生、理科生不考政史地)。这时,需要对考试接口进行细化,分为基础科考试接口、文科考试接口和理科考试接口;学生类实现基础科考试接口;文科生、理科生另外各自实现文科考试接口、理科考试接口。

2.3 依赖倒转原则(Dependence Inversion Principle)

目的

避免需求变化导致过多的维护工作

含义

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

解决

面向接口编程,使用接口或者抽象类制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

依赖关系三种传递方式

  • 接口传递(依赖)
  • 构造方法传递(依赖)
  • setter方式传递(聚合)

实例

母亲类Mother有讲故事方法TellStory,依赖一个Book类输入,并使用了Book类的getContent方法以便讲故事。那么下次需要母亲讲报纸上的故事、手机上的故事时,原有接口无能为力。这时,抽象一个包含getContent方法的IReader基类,Book、Newspaper、Cellphone各自实现。母亲的TellStory方法接受一个IReader实例,并调用getContent方法即可。

2.4 里氏替换原则(Liskov Substitution Principle)

目的

避免系统继承体系被破坏

含义:

所有引用基类的地方必须能透明地使用其子类的对象

解决

子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法;子类中可以增加自己特有的方法;当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。如果子类不能完整地实现父类的方法,或者父类的一些方法在子类中已经发生畸变,则建议断开继承关系,采用依赖,聚合,组合等关系代替继承。

实例

已经定义鸟类具有两个翅膀飞的方法;新加入鸵鸟,不会飞,如果覆盖父类的方法,在两个翅膀飞的方法中什么也不做,就违背里氏替换原则,导致所有鸟都不会飞。应该创建并列的两种鸟基类,会飞与不会飞的。前置条件更宽松、后置条件更严格,比如父类返回Map,子类返回HashMap;父类接受HashMap形参,子类接受Map。

2.5 开闭原则(Open Close Principle)

目的

提高扩展性、便于维护

含义

对扩展开放,对修改封闭。即系统进行扩展是被鼓励的,对现有系统代码进行修改是不被支持的。也就是说,当软件有新的需求变化的时候,只需要通过对软件框架进行扩展来适应新的需求,而不是对框架内部的代码进行修改。

解决

设计模式前面6大原则以及23种设计模式遵循的好,开闭原则自然遵守的好。对需求的变更保持前瞻性和预见性,就可以使抽象具有更广泛适用性,设计出的软件架构就能相对稳定。软件需求中易变的细节,通过从抽象派生出实现类来扩展。

2.6 迪米特法则(最少知道原则)(Demeter Principle)

目的

降低类与类之间的耦合

含义

每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。

解决

不发生依赖、关联、组合、聚合等耦合关系的陌生类不要作为局部变量的形式出现在类的内部。

直接的朋友

每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

实例

校长管理老师,老师管理学生。校长需要全体点名时,首先对老师点名,但是不必通过老师获取学生的信息并点名,而应该让老师对各自管理学生的点名,否则校长和学生之间就发生了原本不必要的耦合,这样当学生类发生变化时,既要修改老师类,也要修改校长类。

2.7 合成复用原则(Composite Reuse Principle)

目的

防止类的体系庞大

含义

当要扩展类的功能时,优先考虑使用合成/聚合,而不是继承。

解决

当类与类之间的关系是"Is-A"时,用继承;当类与类之间的关系是"Has-A"时,用组合。

实例

  • 如桥接模式,抽象和实现可以独立的变化,扩展功能时,增加实现类即可;
  • 比如装饰模式,只需要一个类,即可为一类类扩展新功能。

对于显示图形需求,用图形Shape类,和显示Paint类实现。每个Shape类有一个Paint类指针负责图形绘制显示。Paint类派生RedPaint类和BluePaint类,传递给Shape类,实现图形不同颜色绘制,这样图形绘制逻辑和图形绘制实现可独立变化。
某天增加需求,所有的绘制需要加边框,可增加PaintDecorator类,派生自Paint基类,每一个PaintDecorator类有一个Paint对象指针,增加虚函数AddedPaint,重写Paint的绘制方法,增加AddedPaint方法的调用。增加BorderPaintDecorator类,派生自PaintDecorator类,重写AddedPaint方法,增加添加绘制边框代码。这样新增加一个类可以对原始所有画笔类的功能进行扩充。

9

评论区