跳至主要內容

软件设计的三大原则

技术约 1951 字大约 7 分钟

软件设计的三大原则

软件设计的三大原则

KISS (Keep it simple, Stupid)

KISS原则:Keep it simple, Stupid。尽量保持简单,尽可能提高代码的可读性和可维护性

如何写出满足KISS原则的代码

  1. 不用使用大家可能不懂的技术、高级语法糖等方式来实现代码。除非真有很大性能改善,尽可能用简单、直接的实现方式
  2. 不要重复造轮子,要善于使用现成的工具类库
  3. 不要过度优化,过度使用一些奇淫技巧来牺牲代码的可读性。比如位运算代替算术运算、过于底层的函数等等
  4. 站在维护者的角度编写代码,方便后人学习上手

DRY (Don't Repeat Yourself)

DRY原则:Don't Repeat Yourself。不要重复你的代码,各种重复的地方不要偷懒,比如逻辑重复、功能语义重复等等

如何写出符合DRY原则的代码

  1. 使用现成的轮子,不轻易造轮子。写代码前先看看有没有现成的
  2. 减少代码耦合。高度耦合的代码会影响代码的可复用性
  3. 满足单一职责原则:一个模块只干一件事,这些模块就像一块一块的积木,更加容易复用
  4. 业务与非业务逻辑分离:越是跟业务无关的代码越容易复用,尽可能抽出一些通用的框架、类库、组建出来
  5. 通用代码下沉:越底层的代码越通用,越应该设计得足够可复用。杜绝下层调用上层代码,只允许上层调用下层代码
  6. 利用多态、抽象、封装、各种设计模式

YAGNI (You aren’t going to need it)

不要去编写当前用不到的功能:不要过度设计

面向对象编程的思想

封装、继承、多态、抽象

面向对象的七大设计原则

构建高质量、可维护、可扩展软件系统的基石。通常所说的“七大设计原则”主要指经典的 SOLID 原则,再加上两个重要的补充原则。

非必须严格遵守的教条,而是指导我们写出更好代码的灯塔。它们相互联系、相辅相成,在实际开发中,要结合具体场景灵活运用,适度设计,避免过度设计带来的复杂性。

  • 单一职责是基础,它让类变得简单。
  • 开闭原则是目标,让系统易于扩展。
  • 里氏替换接口隔离是实现开闭原则的重要方式。
  • 依赖倒置是实现开闭原则的主要手段,是面向接口编程的核心。
  • 迪米特法则合成复用原则则从降低耦合、提高复用的角度提供了具体方法。

1、单一职责原则SRP

一个类应该只有一个引起它变化的原因。

解释:如果一个类承担了过多职责,任何一个职责的变化都会导致这个类被修改,从而影响其他功能。这降低了类的内聚性,增加了耦合风险。

例如:一个类负责处理用户信息,另一个类负责用户信息的持久化(存储到数据库)。不要将这两个职责放在一个类中。

2、开闭原则OCP

软件实体(类、模块、函数)应该对扩展开放,对修改关闭。

解释:当系统需要增加新功能时,应该通过增加新的代码来实现,而不是修改已有的、稳定的代码。这通常通过抽象和多态来实现

例如:使用抽象和多态,通过继承或实现接口来扩展功能,而不是修改原有类

例如:电脑的USB接口。你可以接入新设备(扩展),但无需拆开主机(修改)。

3、里氏替换原则LSP

任何基类可以出现的地方,子类一定可以出现,且程序的行为不会发生改变。

解释:子类在重写父类方法时,不应该加强前置条件(对输入更严格),也不应该减弱后置条件(对输出更宽松)。否则,在父类类型的引用指向子类对象时,就可能出现意想不到的错误。

例如:父类有一个方法,子类重写该方法时,不能改变父类方法的原意(比如,父类方法是按照某个规则计算,子类重写后完全改变了计算规则,这就违反了LSP)。

4、接口隔离原则

建立多个专用的、细粒度的接口,而不是建立一个庞大臃肿的总接口。

解释:一个类不应该被强迫实现它用不到的方法。这有助于系统解耦,更易重构和变更

例如:一个动物接口有“飞”、“跑”、“游泳”三个方法,但是鸟只会飞和跑,鱼只会游泳。那么鸟和鱼都实现动物接口就不合适,应该将动物接口拆分成“飞行动物”、“陆生动物”、“水生动物”等更具体的接口。

例如,多功能瑞士军刀 vs. 专用螺丝刀。你只想拧螺丝时,不需要剪刀和开瓶器。

5、依赖倒置原则

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

解释:这是实现松耦合的关键。通过面向接口编程,而不是面向具体实现编程,可以让系统更灵活,易于替换和测试。

例如:高层业务逻辑不应该直接依赖具体的数据库操作类,而应该依赖一个抽象的数据库接口,然后由具体的数据库操作类来实现这个接口。

例如,电视(高层)不依赖特定品牌DVD机(低层),而是依赖“视频输入”这个标准接口(抽象)。

6、迪米特法则LOD

一个对象应该对其他对象保持最少的了解。“只与你的直接朋友通信”。最少知道原则

解释:降低类之间的耦合度,提高模块的相对独立性。朋友包括:当前对象本身 (this)

、以参数形式传入当前方法的对象、当前对象的成员变量等等

例如:A类需要调用B类的方法,而B类的方法需要C类的对象作为参数,那么A类不应该直接创建C类的对象,而应该由B类的方法内部去处理。A类只和B类有直接关系,不和C类有直接关系。

例如,你向经理请假,只需找你的直属领导,不需要认识HR总监、财务总监和CEO。

7、合成复用原则CARP

优先使用对象组合(has-a) 或聚合(contains-a),而不是继承(is-a) 来达到软件复用的目的。

解释:继承是白箱复用(破坏了封装),组合是黑箱复用(维持了封装)。组合可以在运行时动态改变行为,比继承更灵活。

例如:汽车不需要“继承”发动机的功能,而是“包含”一个发动机对象:有一个汽车类,需要引擎功能。不应该通过继承引擎类来实现,而应该在汽车类中包含一个引擎类的实例(组合)。因为汽车不是引擎,而是拥有引擎。

上次编辑于: