七种常见的面向对象设计原则

 
设计原则名称 定义 使用频率
单一职责原则 一个类只负责一个功能领域中的相应职责

 四颗星

开闭原则 软件实体应对扩展开发,而对修改关闭  五颗星 
里氏代换原则 所有引用基类对象的地方能够透明地使用其子类的对象  五颗星
依赖倒转原则 抽象不应该依赖于细节,细节应该依赖于抽象  五颗星
接口隔离原则 使用多个专门的接口,而不使用单一的总接口  两颗星
合成复用原则 尽量使用对象组合,而不是继承来达到复用的目的  四颗星
迪米特法则 一个软件实体应当尽可能少地与其他实体发生相互作用  三颗星

 

 

 

 

 

 

 

 

 

 

 

一、单一职责原则:一个类只负责一个功能领域中的相应职责

它强调一个类应该只有一个引起变化的原因。单一职责原则的使用方法:

1. 识别职责:首先,需要仔细分析类的功能,并识别出它承担的各个职责。这些职责可以是类的功能、行为或数据操作等。

2. 分离职责:一旦识别出类的多个职责,就应该将这些职责分离到不同的类中。每个类应该只关注一个职责,并且这个职责应该被完全封装在该类中。

3. 创建新类:对于每个分离出来的职责,可能需要创建新的类来承载它。这些新类应该具有清晰定义的接口和内部实现,以确保它们能够独立完成自己的职责。

4. 保持高内聚:在将职责分离到不同的类之后,要确保每个类都保持高内聚性。这意味着类内部的元素(如属性和方法)应该紧密相关,并且共同协作以完成类的单一职责。

5. 低耦合:除了保持高内聚性外,还应该尽量减少类之间的耦合度。这可以通过使用接口、抽象类和依赖注入等技术来实现。确保类之间的依赖关系清晰且易于管理。

6. 重构现有代码:如果现有的代码违反了单一职责原则,应该考虑进行重构。通过重新组织代码结构、提取方法和创建新类等方式,将职责分离并封装到合适的类中。

遵循单一职责原则的好处包括:

* 提高代码的可读性和可维护性:由于每个类只关注一个职责,因此代码结构更加清晰,易于理解和维护。
* 降低类的复杂性:通过将职责分离到不同的类中,可以降低每个类的复杂性,使其更易于测试和调试。
* 提高系统的可扩展性和灵活性:由于每个类只负责一个职责,因此可以更容易地对其进行修改和扩展,以适应新的需求或变化。

需要注意的是,单一职责原则并不是要求每个类都只能有一个方法或属性,而是强调每个类应该有一个清晰定义的职责,并且这个职责应该被完全封装在类中。在实际应用中,需要根据项目的具体情况和需求来灵活运用这一原则。

 

二、开闭原则:软件实体应对扩展开发,而对修改关闭

这意味着软件应该能够在不修改其源代码的情况下进行扩展。以下是开闭原则的使用方法:

1. 抽象化设计:
- 设计时,应首先识别出可能变化的点,并将这些点抽象化为接口、抽象类或基类。
- 通过定义清晰的抽象接口,我们可以确保系统的稳定性,因为具体的实现细节被隐藏在接口之后。

2. 面向接口编程:
- 在编写代码时,应始终依赖于抽象接口,而不是具体的实现类。
- 这样,当需要添加新功能或修改现有功能时,我们只需要创建新的实现类,而无需修改现有的代码。

3. 扩展而非修改:
- 当需要添加新功能时,应通过创建新的类来实现,而不是修改现有的类。
- 这意味着新的功能应该通过扩展现有系统来实现,而不是通过修改现有代码。

4. 使用继承和多态:
- 继承和多态是面向对象编程的重要特性,它们可以帮助我们实现开闭原则。
- 通过继承,我们可以创建新的子类来扩展系统的功能。
- 通过多态(重载、重写、接口),我们可以确保系统能够透明地使用这些子类,而无需关心具体的实现细节。

5. 遵循单一职责原则:
- 开闭原则与单一职责原则相辅相成。确保每个类只有一个职责,这样当需要扩展或修改某个功能时,我们可以更容易地定位到相关的类。

6. 使用设计模式:
- 设计模式是实现开闭原则的有力工具。例如,工厂模式、策略模式、模板方法等都可以帮助我们在不修改现有代码的情况下扩展系统的功能。

通过遵循开闭原则,我们可以构建出更加灵活、可维护和可扩展的软件系统。这有助于降低系统的维护成本,提高开发效率,并使得系统能够更好地适应未来的变化。

 

三、里氏代换原则:所有引用基类对象的地方能够透明地使用其子类的对象

    遵循里氏代换原则,可以确保在程序中使用基类的地方可以无缝地替换为子类,而不会导致程序行为的改变。在设计过程中,应尽量从抽象类继承,而不是从具体类继承,以更好地利用里氏代换原则的优势。这有助于提高程序的可靠性、可维护性和可扩展性。同时,也有助于降低代码出错的可能性,提高软件的质量。

里氏代换原则的主要使用方法如下:

1. 子类扩展父类功能:子类可以扩展父类的功能,但不应改变父类原有的功能。这意味着子类在继承父类时,除了添加新的方法实现新增功能外,应尽量避免重写父类的方法。
2. 实现抽象方法:子类可以实现父类的抽象方法,但不应覆盖父类的非抽象方法。这样可以确保子类在替换父类时,不会破坏原有的程序逻辑。
3. 增加特有方法:子类中可以增加自己特有的方法,以扩展功能。
4. 注意方法重载与重写:当子类的方法重载或重写父类的方法时,需要特别注意方法的前置条件和后置条件。子类方法的前置条件(即输入参数)应比父类方法更宽松,而后置条件(即方法返回的结果或产生的副作用)应与父类方法保持一致或更严格。

 

四、依赖倒转原则:抽象不应该依赖于细节,细节应该依赖于抽象

它指导我们如何正确地消除模块间的依赖关系,实现更加灵活和可维护的代码结构。以下是依赖倒转原则的使用方法:

1. 抽象化依赖:
- 依赖倒转原则强调将模块间的依赖关系倒置为依赖抽象类或接口,而不是具体的实现类。
- 这意味着高层模块不应该依赖于低层模块的具体实现,而是应该依赖于它们的抽象。

2. 使用接口和抽象类:
- 在代码中,应尽量使用接口和抽象类来声明变量类型、参数类型、方法返回类型等,而不是使用具体的类。
- 这样做的好处是,当需要更换具体的实现时,只需要修改依赖的接口或抽象类的实现,而不需要修改所有使用到该具体类的代码。

3. 避免直接依赖具体类:
- 在编写代码时,应尽量避免直接从具体类派生新的类,或者让类直接依赖于具体类。
- 相反,应该通过接口或抽象类来建立依赖关系,这样可以更加灵活地更换实现,而不需要修改大量的代码。

4. 依赖注入:
- 依赖注入是实现依赖倒转原则的一种常见方式。
- 通过构造函数、方法参数或属性等方式,将依赖的接口或抽象类的具体实现注入到需要它的类中,从而实现了对具体实现的解耦。

5. 遵循里氏替换原则:
- 里氏替换原则(Liskov Substitution Principle,LSP)是依赖倒转原则的补充。
- 它强调子类必须能够替换其基类,并且替换后,程序的行为不会发生变化。
- 在使用继承时,应遵循里氏替换原则,确保子类能够正确地替换父类,并保持程序的正确性。

通过遵循依赖倒转原则,我们可以降低模块之间的耦合度,提高系统的可维护性和可扩展性。这使得代码更加灵活,更容易适应需求的变化和技术的演进。同时,依赖倒转原则也是实现开闭原则的重要手段之一,有助于我们在不修改现有代码的情况下添加新功能或修改现有功能。

 

五、接口隔离原则:使用多个专门的接口,而不使用单一的总接口

它要求客户端不应该依赖它不需要的接口,或者说一个类对另一个类的依赖性应当是最小的。这意味着我们应该尽量将接口细化,将大接口拆分成多个小接口,客户端只需要知道它感兴趣的方法即可。以下是接口隔离原则的使用方法:

1. 细化接口:
- 分析现有接口,识别出其中不同客户端所需要的不同方法集合。
- 将接口拆分成多个更小的接口,每个接口只包含一组相关的方法,这些方法应该是高度内聚的。

2. 客户端依赖最小化:
- 客户端(即使用接口的类)应该只依赖它实际需要的接口,而不是一个包含众多方法的庞大接口。
- 通过这种方式,客户端的代码将更为简洁,并且减少了不必要的依赖。

3. 避免接口污染:
- 接口污染是指接口中包含客户端不需要的方法,这增加了客户端的复杂性。
- 通过细化接口,我们可以避免接口污染,确保每个接口都只为特定的客户端提供所需的方法。

4. 使用委托或适配器:
- 在某些情况下,可能无法直接拆分接口,但可以通过委托或适配器模式来实现接口隔离。
- 委托模式允许一个对象将请求委托给另一个对象来执行,而适配器模式可以将一个类的接口转换为客户端所期望的另一个接口。

5. 考虑扩展性:
- 在设计接口时,应考虑到未来的扩展性。
- 尽量避免设计过于庞大或复杂的接口,因为它们可能难以维护和扩展。

6. 持续重构:
- 随着项目的进展和需求的变化,可能需要不断地对接口进行重构,以确保它们仍然符合接口隔离原则。
- 在重构过程中,要仔细评估每个接口的使用情况,并根据需要进行拆分或合并。

通过遵循接口隔离原则,我们可以提高代码的可读性、可维护性和可扩展性。它有助于减少类之间的耦合度,使得每个类都更加专注于自己的职责。同时,这也使得代码更加灵活,更容易适应未来的变化。

 

六:合成复用原则:尽量使用对象组合,而不是继承来达到复用的目的

它强调通过对象组合(has-a)或对象聚合(contains-a)的方式来实现代码复用,而不是通过继承关系。这种方式可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较小。以下是合成复用原则的使用方法:

1. 识别可复用的对象:
- 在设计系统时,首先要识别出那些可以被复用的对象或组件。这些对象或组件通常具有稳定的接口和功能,可以在多个上下文中共享。

2. 使用组合或聚合关系:
- 在新的对象或类中,通过组合或聚合关系来使用这些可复用的对象。组合关系表示“has-a”关系,即新对象包含其他对象作为其成员;聚合关系则是一种特殊的组合关系,表示整体与部分的关系。

3. 委派调用已有方法:
- 新的对象或类通过委派调用已有对象的方法来实现复用。这意味着新对象不需要重新实现已有对象的功能,而是直接利用已有对象的方法。

4. 优先使用已存在对象:
- 在创建新对象时,应优先使用已存在的对象来达到复用的目的。这有助于减少系统的开销,并提高资源的利用率。

5. 遵循单一职责原则:
- 合成复用原则常与单一职责原则相结合使用。确保每个对象或类都只有一个职责,这样它们更容易被复用和组合。

6. 避免过度使用继承:
- 继承虽然是一种实现代码复用的方式,但过度使用继承可能导致系统变得僵硬和难以维护。因此,在可能的情况下,应优先考虑使用合成复用原则来替代继承。

通过遵循合成复用原则,我们可以构建出更加灵活、可维护和可扩展的软件系统。这有助于降低系统的维护成本,提高开发效率,并使得系统能够更好地适应未来的变化。

 

七:迪米特原则:一个软件实体应当尽可能少地与其他实体发生相互作用

迪米特原则,也被称为最少知识原则(LKP),主张一个类应该对其他类有尽可能少的了解。为了遵循这一原则,需要确保一个对象只与它直接相关的其他对象通信。下面是遵循迪米特原则的一些方法:

1. 限制方法可见性:只公开必须的方法,将其他方法设置为私有,这样就能限制其他类对该类的访问。
2. 避免使用全局变量:全局变量会使得类之间的耦合度增加,因此应尽量避免使用。
3. 谨慎使用继承:继承会使得子类依赖于父类,因此应谨慎使用,避免不必要的依赖。
4. 使用合成复用原则:通过组合而非继承来复用代码,这样能够降低类之间的耦合度。
5. 引入中间层:在类之间引入中间层,这样可以降低类之间的耦合度,使得系统更易于维护。

遵循迪米特原则能够降低类之间的耦合度,使得系统更易于维护和扩展。

posted @ 2024-05-25 17:06  LXLR  阅读(95)  评论(0编辑  收藏  举报