软件架构设计有七大原则,分别是:
1.开闭原则
2.依赖倒置原则
3.单一职责原则
4.接口隔离原则
5.迪米特法则(最小知道原则)
6.里氏替换原则
7.合成/聚合复用原则
下面分别具体说明:
1.开闭原则 :对扩展开放,对修改关闭
说的是,再设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展.
换言之,应当可以在不必修改源代码的情况下改变这个模块的行为,在保持系统一定稳定性的基础上,对系统进行扩展。
例如:一般软件功能的升级就需要符合开闭原则,即不去修改原来的代码,而是去增加新功能。
2.依赖倒置原则 :实现尽量依赖抽象,不依赖具体实现。
该原则有以下三点说明
1、高层模块不应该依赖于底层模块,两者都应该依赖于抽象,
2、抽象不应该依赖于细节,即具体实现类。
3、细节应该依赖于抽象。
这样带来的好处,可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并且可以降低修改程序所造成的的风险。
例如:我们在日常开发中拿到需求之后,一般都是面向接口编程,先设计出顶层,在细节的来设计代码的结构。(以抽象为基准比以细节为基准搭建起来的架构要稳定的多)
3.单一职责原则 :对于一个类而言,应该仅存在一个可以引起类变化的原因。
从概念来说可能不大好理解,简单的来讲,就是我们平时在编程的时候,会在一个类上添加各种各样的功能。当未来这些功能需要修改时,你不得不一遍又一遍的修改这个类,而且有可能导致其他的功能发生问题,维护起来很麻烦,很难复用,耦合性很大。
如果我们将这些功能分别用不同的类来实现,进行解耦,后期的需求变更和维护就会互不影响,能够降低类的复杂度,提高可读性,总的来讲就是一个类、接口、方法只负责一项职责
4.接口隔离原则:客户端不应该依赖它不需要的接口,类之间的依赖关系应该建立在最小的接口上。
这个原则指导我们在设计接口时应当注意一下几点:
1、一个类对一类的依赖应该建立在最小的接口之上。
2、建立单一接口,不要建立功能繁多的总接口。
3、尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)。
该原则符合高内聚低耦合的设计思想,可以使类具有很好的可读性、可扩展性和可维护性。我们在设计接口的时候,应该多花时间思考,既要考虑到业务模型,还需要为以后可能发生的变更做出一些预判。
5.迪米特法则(最小知道原则):一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合。
由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。迪米特法则不希望类之间建立直接的联系。如果有真的需要建立联系的,也希望能通过他的友元类来转达。
迪米特原则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类
。
6.里氏替换原则: 一个软件实体如果适用一个父类的话,那一定是适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。
即任何基类可以出现的地方,子类一定可以出现。里氏代换原则是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受影响时,基类才能被真正复用,而衍生类也能够在积累的基础上增加新的行为,里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。在基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
当满足继承的时候,父类肯定存在非私有的成员,子类肯定是得到了父类的这些非私有成员(假设,父类的成员全部是私有的,那么子类没办法从父类继承任何成员,也就不存在继承的额概念了)。既然子类继承了父类的这些非私有成员,那么父类对象也就可以在子类对象中调用这些非私有成员。所以,子类对象可以替换父类对象的位置。
在里氏带环原则下,当需求有变化时,只需继承,而别的东西不会改变。由于里氏代换原则才使得开放封闭称为可能。这样使得子类在父类无需修改就可以扩展。
我们总结一下:子类可以扩展父类的功能,但不能改变父类原有的功能。
1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
2、子类中可以增加自己特有的方法。
3、当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松。
4、当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。
使用里氏替换原则有以下优点:
1、约束继承泛滥,开闭原则的一种体现。
2、加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高程序的维护性、扩
展性。降低需求变更时引入的风险
7.合成/聚合复用原则:尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。
换句话说,就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分,新的对象通过这些对象的委派达到复用已有功能的目的。
该原则可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
总结:学习软件设计原则,千万不能形成强迫症。碰到业务复杂的场景,我们需要随机应变。
在实际开发过程中,并不是一定要求所有代码都遵循设计原则,我们要考虑人力、时间、成本、质量,不是刻意追求完美,
要在适当的场景遵循设计原则,体现的是一种平衡取舍,帮助我们设计出更加优雅的代码结构