面向对象开发、设计,一般情况下应遵循以下七大设计原则,单一职责原则、开放封闭原则、里氏替换原则、依赖倒置原则、接口分隔原则、组合/聚合复用原则、迪米特原则。遵循这些设计原则能使我们设计的系统更具稳定性和可扩展性,增强了系统可维护性。这七大原则可以分为以下两部分:
设计目标:开放封闭原则(良好的扩展)、里氏替换原则(合理的继承)、迪米特原则(高内聚低耦合)
设计方法:单一职责原则(只负责自己改管的事)、依赖倒置原则(降低依赖)、接口分隔原则(合理设计接口)、组合/聚合复用原则(多封装、少继承)
一个模块或类应该专注于单一的职责,如果一个模块或类柔和了多个职责,那么一个职责的变动可能会影响另一个职责。单一职责原则降低了模块或类之间的耦合性,增强了代码的可复用性,其核心思想就是让一个软件实体(模块、类、方法等)有且仅有一个职责,其强调软件实体的职责单一。一般来说划分单一职责的标准是引起软件实体改变的原因有且仅有一个。
优点:
耦合性:单一职责原则强调一个软件实体只有一个职责,这最大限度的降低了对象之间的耦合性;
复杂性:单一职责原则还降低软件实体的复杂性;
可读性:单一职责原则提高了软件实体的可读性;
维护性:单一职责原则提供了系统的可维护性。
开闭原则强调软件实体(模块、类、方法等)应该对扩展开放,对修改关闭。即每次发生变化时应该通过扩展代码来实现类的增强,而不是修改原有的代码。符合开闭原则一种好的设计方式就是面向接口编程,对功能设计要尽可能的抽象(接口定义),模块之间的通信也要通过接口来通信。
优点:
稳定性:开闭原则要求扩展功能时不能修改原有的代码,这可让软件系统在变化中保持稳定,增强系统稳定性;
扩展性:开闭原则要求对扩展开放,通过扩展增加或改变原有的功能,这是系统保持了灵活的可扩展性。
系统中所有使用基类的地方都可以用子类来替换,而系统功能保持正常。其核心思想就是子类可以扩展父类的功能,但不能改变父类的原有功能。其强调合理的设计继承关系,不能随便进行继承造成继承泛滥,在进行设计时尽量从抽象类继承而不是具体的类。从继承等级树来看,所有的叶子节点都应该是具体的实现类,而所有的枝干节点应该都是抽象类或接口,当然这只是一般指导原则,并不是绝对的设计原则,在实际使用时还是得具体问题具体分析。
优点:
约束继承泛滥,是开闭原则的一种体现;
加强程序的健壮性,提高程序的维护性和可读性。
一个软件实体应该只与直接相关联的对象通信,而不要与“陌生对象”通信。其思想就是一个软件实体尽可能少的与其他实体发生相互作用,每个软件实体对其他软件实体都只有最少的了解。其初衷就是达到高内聚低耦合的目的,减少对象之间的依赖。通俗的理解就是一个类应该尽可能少的与其他类建立依赖关系,必须要建立关系时也可以通过间接的方式来建立联系,比如可以通过一个中介类来建立两者之间的联系,当然这增加了系统的复杂度,实际使用时还是得具体问题具体分析。
通过迪米特原则让我们了解到,在设计时应该严格控制一个软件实体的公共对象,比如对于一个类必须要暴露的方法才暴露,不必要暴露的就不暴露,要尽量减少“public”的使用。
优点:
高内聚低耦合
不能强迫用户去依赖那些他们不使用的接口,通俗的说就是定义多个专门的接口优于定义一个笼统的接口,接口设计应该遵循最小接口设计原则。
接口分离原则强调
一个类对接口的依赖应当建立在最小接口的原则上;
应当建立单一接口,尽量细化接口,但也要适度,避免产生大量的细小接口,造成接口泛滥。
优点:
符合高内聚低耦合的思想,从而使系统具有更好的可读性、可扩展性和可维护性。
高层模块不应该依赖于底层模块,他们都应该依赖于抽象;抽象不应该依赖于具体实现,具体实现应该依赖于抽象;应该面向接口编程。
高层模块与低层模块:在一个应用程序中,我们有一些低层次的类,这些类实现了一些基本的或初级的操作,我们称之为低层模块;另外有一些高层次的类,这些类封装了某些复杂的逻辑,并且依赖于低层次的类,这些类我们称之为高层模块。
对于传统的面向过程编程而言,高层模块总是依赖于底层模块的,这使得开发软件重用性差,维护困难。而依赖倒置原则强调的是高层模块不应该直接依赖于底层模块,而应该依赖于抽象(接口、抽象类等)。
优点:
减少类间的耦合,提高系统稳定性,提高代码可读性和可维护性。
面向对象设计中有两种办法可以达到功能复用的目的:一是通过组合/聚合;二是通过继承。组合/聚合复用原则强调尽量使用组合/聚合,而不要使用继承。即在一个新类中使用已有的类,使之成为新类的一部分,新类通过使用这些类达到功能复用的目的。就是说尽量使用组合/聚合,而不是使用继承来达到复用的目的。
优点:
组合/聚合复用是“黑箱”复用,他不知道复用对象的具体实现细节,而继承是“白箱”复用,父类的实现细节都会暴露给子类;
组合/聚合复用更好的支持封装,避免了因功能复用而造成的继承泛滥。