设计模式是一种经过验证的、被广泛应用的解决特定问题的软件设计方案,它提供了一种在软件设计中反复使用的解决方案。设计模式通常描述了一个问题的情境、解决方案和解决方案的优点和缺点。设计模式不是一种具体的编程语言特性或库,而是一种通用的设计思想和方法。
设计模式的出现是为了解决软件设计中的一些常见问题,如代码重复、可维护性、灵活性和扩展性等。设计模式可以帮助开发人员更加高效地设计软件,使得软件结构更加清晰、易于维护和扩展。
如此之看,设计模式显得尤为重要, 平时我们自己都在强调编程思想是多么重要,可是到了自己写代码的时候,又是大量的if/else, switch/case自己都觉得很low。或许大家都听过设计模式或者学过一些,但是都不知道咋应用到自己的代码里,本专题将会结合一些实际案例给大家讲解如何合理运用设计模式来改善我们的代码质量。
设计模式的目的 :
编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重 用性,灵活性
等多方面的挑战,设计模式是为了让程序(软件),具有更好
- 代码重用性 (即:相同功能的代码,不用多次编写)
- 可读性
(即:编程规范性, 便于其他程序员的阅读和理解)- 可扩展性 (即:当需要增加新的功能时,非常的方便,称为可维护)
- 可靠性(即:当我们增加新的功能后,对原来的功能没有影响)
- 使程序呈现高内聚,低耦合的特性
分享金句:
设计模式包含了面向对象的精髓,“懂了设计模式,你就懂了面向对象分析和设计 (OOA/D)的精要” Scott Mayers
在其巨著《Effective C++》就曾经说过:C++老手和 C++新手的区别就是 前者手背上有很多伤疤
设计模式七大原则
设计模式原则,其实就是程序员在编程时,应当遵守的原则,也是各种设计模
式的基础(即:设计模式为什么这样设计的依据)
设计模式常用的七大原则有:
- 单一职责原则
- 接口隔离原则
- 依赖倒转(倒置)原则
- 里氏替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
单一职责原则
单一职责原则是指一个类或模块应该只有一个职责,即一个类或模块只应该有一个引起它变化的原因。
这个原则可以帮助开发者更好地组织代码结构,使得每个类或模块的职责更加清晰,更加易于维护和扩展。如果一个类或模块承担了过多的职责,那么当其中任意一个职责发生变化时,就可能会影响到其他职责,从而导致代码的不稳定性和难以维护。
实践单一职责原则可以使得代码更加具有可读性和可维护性,也能提高代码的复用性。在实际编码中,可以通过以下方式来实现单一职责原则:
将类或模块的职责分离:将一个职责过多的类或模块拆分成多个类或模块,每个类或模块只承担一个职责。
降低类或模块之间的耦合性:避免不必要的依赖关系,尽量使用接口或抽象类来定义类或模块之间的通信方式,以降低它们之间的耦合性。
对类或模块进行抽象和封装:将类或模块中的通用功能抽象出来,形成一个单独的模块,使得这些通用功能可以在多个类或模块中被复用。
里氏替换原则
里氏替换原则是面向对象设计中的一个基本原则,它是由Liskov提出的,因此也被称为Liskov Substitution Principle(LSP)。这个原则定义为:所有引用基类的地方必须能够透明地使用其子类的对象,即子类必须能够替换掉它们的父类。
这个原则的核心思想是:子类应该可以替换父类并且能够在不影响程序正确性的情况下,增加新的行为(方法)。
如果一个类违反了里氏替换原则,那么在使用这个类时,可能会引入一些意想不到的行为或结果,导致系统出现错误或异常。因此,遵守里氏替换原则可以使得代码更加灵活、可扩展和易于维护。
遵循里氏替换原则的实现方式如下:
子类必须实现父类的所有抽象方法,或者说子类必须可以完全替换父类。
子类可以有自己的方法,但是不能影响父类原有的行为。
子类的方法可以有自己的特殊实现,但是必须满足父类的前置条件、后置条件和约束条件。
总之,里氏替换原则提醒我们在继承时需要注意,不要破坏原有的程序功能和逻辑,尽量使用接口、抽象类和组合等方式来达到代码的灵活性和可扩展性。
依赖倒置原则
依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一个重要原则,其核心思想是高层模块不应该依赖底层模块,它们应该依赖于抽象接口(或抽象类)。同时,抽象接口也不应该依赖于具体实现,而是具体实现应该依赖于抽象接口。
依赖倒置原则主要通过以下方式来实现:
通过抽象类或接口来定义公共的行为。
高层模块不应该直接依赖于具体实现类,而是应该依赖于抽象接口。
具体实现类应该实现对应的接口,而不是继承抽象类。
依赖倒置原则的好处是能够降低代码的耦合度,提高代码的灵活性和可维护性。当需要改变某个模块的具体实现时,只需要改变具体实现类而不需要改变高层模块的代码,这样可以减少代码的改动范围,提高代码的可维护性和扩展性。
除此之外,依赖倒置原则还可以帮助我们更好地实现“面向接口编程”,提高代码的可读性和可理解性。
接口隔离原则
接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的一个基本原则,其核心思想是:客户端不应该依赖于它不需要的接口。该原则的目标是降低类之间的耦合度,使得类更加灵活、可扩展和易于维护。
接口隔离原则要求我们设计精简、高内聚的接口,一个类不应该强制性地依赖于它不需要的方法。换言之,我们应该将一个大的接口拆分成多个小的接口,每个接口只包含一组相关的方法,这样可以减少类与类之间的依赖关系,降低代码的耦合度,提高代码的灵活性和可扩展性。
接口隔离原则可以通过以下几个方面来实现:
将一个大的接口拆分成多个小的接口,每个接口只包含一组相关的方法。
接口中的方法应该是客户端需要的,不要强制客户端实现不需要的方法。
将接口尽可能地抽象化,避免暴露细节,保持接口的简洁性。
接口设计应该满足“单一职责原则”,即每个接口只有一个职责。
总之,接口隔离原则是面向对象设计中非常重要的一个原则,它能够有效地降低代码的耦合度,提高代码的灵活性和可维护性。遵循接口隔离原则可以使得代码更加清晰、简洁、易于理解和扩展。
迪米特法则
迪米特法则(Law of Demeter,LoD),也称为最少知识原则(Least Knowledge Principle,LKP),是面向对象设计中的一个重要原则,其核心思想是:一个对象应该对其他对象保持最少的了解,它只需要和它直接的朋友交流。这个朋友指的是该对象的成员变量、方法参数、方法返回值等。
迪米特法则的主要目的是降低系统的耦合度,提高系统的可维护性和可扩展性。该原则要求我们在设计系统时,遵循以下两个原则:
只和直接的朋友通信:一个对象只应该和它直接的朋友(成员变量、方法参数、方法返回值等)交流,不应该向外暴露更多的信息。
不要向外暴露过多的细节:一个对象的实现细节不应该暴露给外部,只需要向外提供必要的接口就可以了。
迪米特法则可以通过以下几个方面来实现:
合理设计类之间的关系,避免出现过于紧密的耦合关系。
将复杂的业务逻辑封装到一个单独的类中,对外只提供必要的接口。
将接口尽可能地抽象化,避免暴露细节,保持接口的简洁性。
迪米特法则的好处是可以有效地降低系统的耦合度,提高系统的可维护性和可扩展性。当系统的模块之间的耦合度降低时,修改一个模块对其他模块的影响也会降低,从而提高了系统的灵活性和可维护性。同时,迪米特法则还可以帮助我们更好地实现“面向接口编程”,提高代码的可读性和可理解性。
开闭原则
开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一个基本原则,其核心思想是:一个软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着我们应该通过增加新的功能来扩展软件实体的功能,而不是通过修改现有的代码来实现。
开闭原则的主要目的是降低软件的维护成本,提高软件的可扩展性和可复用性。如果一个软件实体不遵循开闭原则,那么每次添加新功能都需要修改已有的代码,这样会增加系统的复杂性,降低系统的可维护性和可扩展性。
开闭原则可以通过以下几个方面来实现:
使用抽象化和多态来实现扩展:通过定义抽象的接口和实现类,利用多态机制来实现扩展,可以避免修改已有的代码。
使用接口而非实现类进行编程:在编程时尽量使用接口而不是具体的实现类,这样可以避免依赖于具体的实现,提高代码的可扩展性。
使用设计模式:使用设计模式(如策略模式、模板方法模式等)可以帮助我们更好地遵循开闭原则,提高代码的可维护性和可扩展性。
开闭原则的好处是可以有效地降低软件的维护成本,提高软件的可扩展性和可复用性。遵循开闭原则可以使得代码更加清晰、简洁、易于理解和扩展,同时也可以提高代码的可读性和可理解性。
组合/聚合复用原则
组合/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)是面向对象设计中的一个基本原则,其核心思想是:优先使用组合/聚合关系来达到代码复用的目的,而不是继承关系。
组合关系指的是包含和被包含的关系,例如一个部门包含多个员工;而聚合关系指的是整体和部分的关系,例如一家公司由多个部门组成。在组合/聚合关系中,一个对象通常作为另一个对象的成员变量存在,通过对成员变量的组合或聚合来实现代码的复用。
相比于继承关系,组合/聚合关系具有更大的灵活性和可扩展性。使用组合/聚合关系可以使得代码更加清晰、简洁、易于维护和扩展,同时也可以避免继承带来的副作用,如父类的修改可能会影响所有的子类。
组合/聚合复用原则可以通过以下几个方面来实现:
优先使用组合/聚合关系来实现代码复用:在设计类之间的关系时,优先考虑使用组合/聚合关系来实现代码复用,而不是使用继承关系。
将公共的功能抽象成接口:将公共的功能抽象成接口,通过组合/聚合关系来实现代码复用,并使用接口来描述公共的功能。
避免使用继承关系实现代码复用:避免在设计中过度使用继承关系,因为继承关系可能会导致代码的耦合性增加,同时也会限制代码的可扩展性和可维护性。
组合/聚合复用原则的好处是可以使得代码更加灵活、可扩展、易于维护和理解。使用组合/聚合关系可以避免继承带来的副作用,同时也可以提高代码的可读性和可理解性。