不同的设计模式对应不同的需求,而设计原则则是面向对象设计不变的定律。设计模式遵循这些基本的原则,设计原则又由设计模式来实现,二者相辅相成。在面向对象程序设计中遵守这些原则可以使我们的代码更灵活,更易于复用和拓展。
下面是对这张导图的详细介绍:
1.单一职责原则
单一职责原则(Single Responsibility Principle, SRP),就是指一个类或者模块应该有且只有一个改变的原因。即一个类有且只有一个职责
(可以将多个功能集成于一体,但是你不能这样做。它会给使用和管理都带来很多问题)
原理分析:类包含多个职责,代码会变得耦合。如果一个类承担了多于一个的职责,那么引起它变化的原因就会有多个,就等于把这些职责耦合在了一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏。
职责:被表述为“变化的原因”。
职责扩散:因为某种原因,某一职责被分化为颗粒度更细的多个职责了。
核心:SRP就是将东西分到不能再分(把具有多个职责的类拆分为多个类,一个类中的方法都是为了一个目的),再集中化管理和复用
2.开闭原则
开闭原则(Open Closed Principle OCP)具有理想主义色彩,它是面向对象设计的终极目标。在面对需求时,对程序的改动是通过增加新代码进行的,而不是更改现有代码。
(不需要知道身体的内部构造、也不需要对身体做任何改动,就可以通过穿衣服来改变外观)
在系统设计的时候,完全的封闭是不可能的,但还是要尽量做到这一点。对于软件系统的功能扩展,可以通过继承、重载或者委托等手段实现。里氏代换原则(LSP)、依赖倒转原则(DIP)、接口隔离原则(ISP)以及抽象类、接口等,都可以看作开闭原则的实现方法
核心:核心模块或类在需要扩展的时候不应该被修改,抽象是关键
3.里氏代换原则
里氏代换原则(Liskov Substitution Principle LSP),子类必须能替换它们的基类。即使用基类引用的函数必须能够使用派生类而无须了解派生类。
(鸵鸟是鸟,但它不会飞。这样的继承在使用过程中将会造成难以预料的后果)
应当从Bird中分出一个不会飞的类由Ostrich继承
它是继承复用的基础,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是开闭原则的补充,是对实现抽象化的具体步骤的规范。
举例:圆和椭圆,圆是椭圆的一个特殊子类。因此任何出现椭圆的均可由圆来代替,但反之不行。
核心:LSP仅仅是一种确保继承被正确使用的方法。“继承”常常被描述为“is a”的关系,违反了LSP继承就会混乱,基于父类编写的单元测试代码将无法成功运行子类。
4.依赖倒转原则
依赖倒转(Dependency Inversion Principle DIP)高层次的模块不应该依赖于低层次的模块,而是都应该依赖于抽象。面向对象的设计与使用哪种语言编程无关,主要决定因素是程序编写时是针对抽象编程而不是针对细节编程。DIP是面向对象设计的标识。
(当这辆车的车轮坏了时,只需要按照这种车的车轮规格进行更换即可)
汽车应该依赖于抽象的车轮规格,只要符合这个规格的车轮就可以装到汽车上,即做到“可插拔”
核心:关键是抽象,针对接口编程,而不是具体对象
5.接口分离原则
接口分离原则(Interface Segregation Principle ISP):用户不应该被迫依赖他们不使用的接口。采用多个与特定客户类有关的接口比采用一个通用的接口要好。缺少ISP,组件、类的可用性和移植性将大打折扣。
(笔记本上只设计了必要且常用的几个接口,这对我们日常的使用已经足够)
接口太大,或者暴漏的方法太多,从外部看会很混乱。接口包含的方法太多也会降低可复用性,这种包含无用方法的“胖接口”无疑会增加类的耦合。(一个类要给多个客户使用,那么可以为每个客户创建一个接口,然后这个类实现所有的接口;而不要只创建一个接口,其中包含所有客户类需要的方法,然后这个类实现这个接口。)
核心:接口只应该包括必要的方法而不是所有的。ISP确保接口实现自己的职责,从而具有可复用性
6.其它原则
最少知识原则(Least Knowledge Principle LKP)又称迪米特法则(Law ofDemeter LoD):类对其它类知道的越少越好
组合替代继承:用组合比用继承好
共同封闭原则:相关类应该一起打包
稳定抽象原则:类越稳定,就越应该是抽象类
……
小结:
设计模式是一些针对特定场景的通用设计建议,主要内涵是这些设计原则。可以说OOD是“规范”,设计模式是“框架”。设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。所以设计代码的时候,要优先考虑。