为什么要遵守面向对象的设计原则?
这个问题的本质是,我们为什么要学习设计模式这门课?我们在开发功能时,常常有很多种实现方法。当需求确定时,我们可以一步一个脚印的进行编码实现,问题是,如果出现新的需求,或者之前的需求需要修改时,有时候会面临需要大刀阔斧的修改代码的境遇。以至于做了很多无用功,我们更希望在遇到新需求时,可以不用去更改以往的代码,只需要添加少量代码就可以完成任务,这是学习设计模式的根本目的。 如果你提前学习过设计模式原则,你会发现这和开闭原则的描述十分的相似,学习设计模式的目的就是增强系统的可拓展性、稳定性。遵守以下几个原则,可以帮助你完成这一目标。但是正所谓,大道理人人都懂,小情绪难以控制。这些原则类似于一些大道理,起着指导性的思想,需求就像生活中遇到的困难一样,没有一套统一的方法论能解决所有的问题,在面对需求时,需要根据实际情况,制定相应的策略。
单一职责原则
Single Responsibility Principle(SRP)
定义:一个类只负责一个功能领域中的相应职责。
好处:
通俗的讲,就一个类而言,应该只有一个引起它变化的原因。单一原则是实现高内聚、低耦合的指导方针。所谓高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务。模块的内聚反映模块内部联系的紧密程度。一个模块只需做好一件事件,不要过分关心其他任务。这里可以重点讲讲几种不同的耦合。
1)内容耦合。当一个模块直接修改或操作另一个模块的数据,或直接向另一个模块传输数据时,就会发生内容耦合。此时,修改后的模块完全依赖于修改后的模块。类与类之间的直接调用或继承关系就属于这种耦合。应该完全避免内容耦合。关键是不要在类内部直接操作另一个类的对象的数据成员。可以通过在操作类中增加一个函数接口向客户类提供服务来实现。
2)公共耦合是指两个或多个模块一起引用一个全局数据项。
3)控制耦合是指一个模块在接口上发送信号(如开关值、标志量等)来控制另一个模块,并根据信号值来调整接收信号的模块的动作。
4)标记耦合是指复杂的内部数据结构是通过参数在模块之间传递的。数据结构的改变会改变相关的模块。
5)数据耦合是指基本类型的数据通过参数在模块之间传递。
6)非直接耦合就是模块间没有信息传递。
而高内聚、低耦合的系统更加的可靠,且可复用性强
开闭原则
Open-Closed Principle,OCP)
定义:软件实体应对拓展开放,而对修改关闭。
Software entities should be open for extension ,but closed for modification。
好处:
我们希望在不修改原有代码的情况下进行拓展,这样可以减少编写代码的量,并且已经完成的任务不会被破坏。要做到这一点的关键是抽象化,抽象层模块不能再改变。使得软件系统有一定的稳定性和延续性。
里氏代换原则
(LisKov Subsititution Principle,LSP)
子类可以任意的替换父类出现的地方。
严格的定义如下:如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换为O2时,程序P的行为都没有变化,那么类型T2是类型T1的子类型。
好处:
一般使用里氏代换原则的场景是针对一些需要拓展的类或者存在变化的类设计为抽象类,或者接口,并将其作为基类。以便于后续根据需求来拓展这些抽象类,而不用去修改基类对象的代码,贴近开闭原则。
依赖倒转原则
(Dependcy Inversion Principle,DIP)
定义如下:抽象不应该依赖于细节,细节应当依赖于抽象。
好处:
如果说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要机制。在引入抽象层后,系统将具有很好的灵活性。在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样,如果在系统行为发生变化时,只需要对抽象层进行拓展,并修改配置文件即可。
接口隔离原则
(Interface Segregation Pricipele,ISP)
定义:使用多个专门的接口,而不适用单一的总接口。
ISP表达的意思是指接口仅仅提供客户端需要的行为,客户端不需要的细节则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供太大的接口。
合成复用原则
(Composite Reuse Principle CRP)
定义:尽量使用对象组合,而不是继承来达到复用的目的。
在面向对象设计中,可以通过两种基本方法在不同的环境中复用已有的设计和实现,即通过组合/聚合的关系或通过继承。根据合成复用原则我们应该先考虑使用组合/聚合的关系,这样可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其它类造成的影响相对较少。其次考虑使用继承,在继承时,需要遵守里氏代换原则。滥用继承会增加系统构建和维护的难度,以及系统的复杂度。
迪米特法则
(Law of Demeter,Lod)
定义:一个软件实体应当尽可能少地与其它实体发生相互作用。
这样做的好处是,当一个模块修改时,就会尽量少地影响其它模块,扩展会相对容易一些。