面向对象设计原则
如何同时提高一个软件系统的 可维护性和可复用性是面向对象设计需要解决的核心问题之一。
七种设计原则(高内聚、低耦合)
1、单一职责:
一个类只负责一个功能领域中的相应职责。
初始方案 改进后
2、开闭:
软件实体应对扩展开放,对修改关闭。(抽象化是开闭的关键)
如果系统扩展只涉及到修改配置文件,可认为是符合开闭原则的系统。
改进后
3、里氏替换:
所有引用基类对象的地方能够透明地使用其子类的对象。(定义成员变量、局部变量、返回类型)
里氏替换是实现开闭原则的重要方式之一。在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
改进前 改进后
4、依赖倒转:
抽象不应该依赖细节、细节应该依赖于抽象。
尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明,参数类型声明、方法返回类型声明,以及数据类型的转化等,而不要用具体类来做这些事。
程序中尽量使用抽象层进行编程,而将具体类写在配置文件中。如果系统行为发生变化,只要对抽象层进行扩展,并修改配置文件。
依赖注入(Dependency Injection,DI),当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。构造注入、设值注入和接口注入。
开闭原则是目标、里氏替换原则是基础,依赖倒置是手段。
5、接口隔离:
使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些它不需要的接口。
注意控制接口的粒度、太小会导致系统中接口泛滥,不利于维护;太大,灵活性差,使用不方便。
改进前 改进后
6、合成复用:
尽量使用对象组合(Has-A),而不是继承(Is-A)来达到复用的目的。
首先考虑使用组合/聚合,可以使系统更加灵活,降低类与类之间的耦合度。其次才考虑使用继承,需要严格遵守里氏替换原则,有助于问题的理解,降低复杂度,滥用继承会增加系统构建和维护的难度和系统复杂度。继承复用会破坏系统的封装性,基类细节会暴露给子类,基类变化,子类也不得不发生改变。
7、迪米特法则:(最少知识原则 )
一个软件实体应当尽可能少地与其他实体发生相互作用。
当某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,限制软件实体之间通信的宽度和深度。降低系统耦合度,使类与类之间保持松散的耦合关系。
(1) 当前对象本身(this);
(2) 以参数形式传入到当前对象方法中的对象;
(3) 当前对象的成员对象;
(4) 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
(5) 当前对象所创建的对象。
应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。
(1)在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;
(2)在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;
(3)在类的设计上,只要有可能,一个类型应当设计成不变类;
(4)在对其他类的引用上,一个对象对其他对象的引用应当降到最低。
改进前
改进后