1.开闭原则
软件实体应当对扩展开放,对修改关闭; 大概意思是:在每次需求功能变更时,应该是通过添加代码来实现其效果,而不是通过修改之前的代码来达到目的。这其实是考验我们对需求的理解与对问题的抽象,并设计出可扩展的代码。这样的好处是,避免修改代码造成对先前功能的影响。
2.里氏替换原则
继承必须确保超类所拥有的性质在子类中仍然成立;
也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。特别是运用多态比较频繁时,继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系。
分析:鸟一般都会飞行,如燕子的飞行速度大概是每小时 120 千米。但是新西兰的几维鸟由于翅膀退化无法飞行。假如要设计一个实例,计算这两种鸟飞行 300 千米要花费的时间。显然,拿燕子来测试这段代码,结果正确,能计算出所需要的时间;但拿几维鸟来测试,结果会发生“除零异常”或是“无穷大”,明显不符合预期。
程序运行错误的原因是:几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。正确的做法是:取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。
3.依赖倒置原则
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象;
其核心思想是:要面向接口编程,不要面向实现编程。由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。
它的好处是:
1.降低类间的耦合性
2.提高系统的稳定性
3.减少并行开发引起的风险
4.提高代码的可读性和可维护
在实际编程中只要遵循以下4点:
1.每个类尽量提供接口或抽象类,或者两者都具备
2.变量的声明类型尽量是接口或者是抽象类
3.任何类都不应该从具体类派生
4.使用继承时尽量遵循里氏替换原则
4.单一职责原则
一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分如果一个对象承担了太多的职责,至少存在以下两个缺点:
1.一个职责的修改可能影响另一个职责的功能
2.当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或性能的额外开销
如果遵循单一职责原则将有以下优点:
简单性、可读性、易维护性、可复用性
5.接口隔离原则
客户端不应该被迫依赖于它不使用的方法,一个类对另一个类的依赖应该建立在最小的接口上;
以上两个定义的含义是:要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下 几个优点:
1.提高系统的灵活性和可维护性,降低了系统的耦合性。
2.能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。
6.迪米特原则
只与你的直接朋友交谈,不跟“陌生人”说话
其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。
正确使用迪米特法则将有以下两个优点:
1.降低了类之间的耦合度,提高了模块的相对独立性
2.由于亲合度降低,从而提高了类的可复用率和系统的扩展性
但是,过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。
运用迪米特法则时要注意以下 几 点:
1.在类的结构设计上,尽量降低类成员的访问权限
2.在类的设计上,优先考虑将一个类设置成不变类
3.在对其他类的引用上,将引用其他对象的次数降到最低
4.不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)
7.合成复用原则
尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现;
通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
1.继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用
2.子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护
3.它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化
采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
1.它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用
2.新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口
3.复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象
最后
这 7 种设计原则是软件设计模式中应该尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。