设计模式七个设计原则及其作用
作者:互联网
单一职责原则
一个类应该仅有一个引起它变化的原因。即,一个对象应该之包含一个职责,并且这个职责杯完整的封装在一个类中。
所谓职责是指类变化的原因,如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。
这是最简单、最容易理解却最不容易做到的一个设计原则,用于控制类的粒度大小
作用:1、降低了类的复杂性
2、可读性提高
3、可维护性提高
4、变更引起的风险降低
5、单一职责原则是实现高内聚、低耦合的指导方针
开闭原则(OCP)
软件实体应该对扩展开放,对修改关闭。
开闭原则是面向对象可复用设计的第一块基石,是最重要的面向对象设计原则。
实现开闭原则的关键就在于抽象,采用相对稳定的抽象层+灵活的具体曾。把系统所有可能的行为抽象成一个抽象底层,这个抽象底层规定所有具体实现必须提供的方法特征。
作为系统设计的抽象层,要预见所有可能的扩展,从而使得在任何扩展情况下,系统的抽象底层不需修改;同时。由于可以从抽象底层导出一个或多个新的具体实现,可以改变系统的行为,因此系统设计对扩展是开放的。
开闭原则是一个最基本的原则额,其他原则都是开闭原则的具体形态,是知道设计的工具和方法,开闭原则才是精神领袖。
作用:1、开闭原则有利于进行单元测试
2、开闭原则可以提高复用性
3、开闭原则可以提高可维护性
4、是面向对象开发的要求
接口隔离原则(ISP)
(1)客户端不应该依赖它不需要的接口
(2)类之间的依赖关系应该建立在最小的接口上
接口隔离原则是对接口的使用进行约束的一个原则。
接口分为两种:
(1)类接口:使用interface定义的接口;
(2)实例接口:使用Class定义的类也是一种接口
隔离:
(1)客户端和它不需要的接口隔离,即客户端不使用它不需要的接口,使用该接口的客户端仅需知道与之相关的方法;
(2)每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干,接口中没有多余的方法;
作用:
1、避免接口污染
2、提高灵活性
3、提供定制服务
4、实现高内聚:高内聚就是接口、类、模块中定义了一组相关的行为,接口是对外界的承诺,承诺越少对系统的开发越有利、变更的风险也就越少,同时也有利于降低成本。通过细化接口实现高内聚。
依赖倒置原则(DIP)
高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。
依赖倒置原则基于这样一个事实,抽象稳定,而细节具有多变性,要针对抽象(接口、抽象类)编程,不要正对实现(具体类)编程。
以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定。
利用接口或者抽象类来制定规范和契约,具体细节由实现类完成。
在传递参数(依赖关系)或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行表里类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等。
依赖倒置实现的3种方式:
1、构造注入。通过构造方法声明依赖对象。
2、设值注入(setter注入)。在类中通过Setter方法声明依赖关系。
3、接口注入。在接口的方法种声明依赖对象。
作用:
1、减少类间的耦合性
2、提高系统稳定性、降低并行并发引起的风险
3、提高代码的可读性和可维护性
里氏替换原则(LSP)
所有引用基类的地方必须能透明地使用其子类的对象,即替换成子类后,系统的行为不会发生改变。
继承的优点:
(1)提高代码的重用性,子类拥有父类的方法和属性
(2)提高代码的可扩展性,子类可形似于父类,但异于父类,保留自己的特性。
继承的缺点:
(1)继承是侵入性的。继承关系种,子类拥有父类的所有方法和属性,在一定程度上约束了子类,降低了代码的灵活性。
(2)增加了耦合。当父类的常量、变量或者方法被修改了,需要考虑子类的修改,所以一旦父类有了改动,很可能会造成非常糟糕的结果,要重构大量代码。
(3)降低了代码的灵活性。子类必须拥有父类的属性和方法,增强了对子类的约束。
继承关系要遵守的4个规则:
(1)子类可以实现父类的抽象方法,但不能覆写父类的非抽象方法;
(2)子类中可以增加自己特有的方法,体现子类的个性;
(3)当子类的方法是实现父类的放啊时,(重写、重载或 实现抽象方法)时,方法的前置条件(即方法的输入参数)要比父类的输入参数更宽松或相等。
(4)当子类的方法实现父类的方法时(重写、重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。
作用:
(1)约束继承泛滥,开闭原则的一种体现
(2)加强程序的健壮性,在程序变化时可以做到非常好的兼容性,提高程序的维护性、扩展性
(3)降低需求变更时引入的风险
强调:如果父类中的某些方法在子类中已经发生“畸变”,
则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承,即组合复用原则。
组合复用原则
优先使用对象组合(聚合),而不是继承来达到复用的目的。
在一个新的对象里面,通过关联关系,(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用功能的目的。
即尽量使用组合和聚合而不是继承。
继承复用的缺点:
(1)继承将基类的实现细节暴露给子类,继承复用破坏了封装性,是“白箱”复用。
(2)如果基类的实现发生改变,则子类的实现也不得不发生改变。
(3)从超类继承而来的实现是静态的,不可能再运行时间内发生改变,因此没有足够的灵活性。
使用继承时需要考虑里式替换原则。
Coad法则(使用继承条件)
(1)子类是基类的一个特殊种类,而不是基类的一个角色。有“is-a”关系才符合继承关系,"has-a”关系应当用聚合(关联)来描述。
(2)如果不能肯定一个类将来是否会变成另外一个子类,就不要使用继承(不能确定类的父类)。
(3)子类具有扩展基类的责任,而不是具有置换掉(override)或注销掉
(Nullify)基类的责任。如果一个子类需要大量的置换掉基类的行为,那么这个类就不应该是这个基类的子类。
(4)只有在分类学角度上有意义时,才可以使用继承。不要从工具类继承。
错误的使用继承而不是合成(聚合)的一个常见原因是错误地把“has-a"当成了“is-a"。“is-a"代表一个类是另外一个类的一种;“has-a"代表一个类是另外一个类的一个角色,而不是另外一个类的特殊种类。
例如,如果“人”是一个类,把“经理”、“学生”、“主任”和“部长”设计为“人”的子类,这种设计是错误的。因为把“角色”的等级结构和“人”的等级结构混淆了。“经理”、“学生”、“主任”和“部长”是一个人的角色,一个人同时拥有多个角色。
如果采用继承关系来设计,因为单继承原因,如果一个人是“学生”则不能是“经理”,这显然不合理。正确的设计的有个抽象类“角色”,“人”可以拥有多个角色。
作用:(1)新对象存取成员对象的唯一途径是通过成员对象的接口,这种复用是黑箱复用,使系统更加灵活,降低类与类之间的耦合度;
(2)成员对象的内部细节对新对象是不可见的,这种复用支持封装,减少依赖,一个类的变化对其他类造成的影响相对较少;
(3)每一个新的类可以将焦点集中在一个任务上;
(4)种种复用可以在运行时动态进行,新对象可动态引用与成员对象类型相同的对象。
不足之处:这种方式建造的系统会有较多的对象需要管理。
迪米特法则(LoD)
一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。或者:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
含义:
(1)迪米特法则要求在设计系统时,应该尽量咸少对象之间的交互;
(2)如果两个对象之间不必彼此直接通信,那么这两个对象就不应该发生任何直接的相互作用;
(3)如果其中一个对象需要调用另一个对象的方法,可以通过“第三者”转发这个调用;
(4)通过引入一个合理的“第三者”来降低现有对象之间的耦合度。
迪米特法则强调不和“陌生人”说话,任何一个对象,如果满足下面条件之一,就是当前对象的“朋友”﹔否则就是“陌生人”。
朋友圈:
(1)当前对象本身( this ) ;
(2)当前对象方法中的参数;
( 3)当前对象的实例变量直接引用的对象;
( 4)当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友;
(5)当前对象方法中所创建的对象。
迪米特法则对设计类提出了4个要求:
(1)优先考虑将一个类设置成不变类;
(2)尽量降低一个类的访问权限;
(3 )谨慎使用Serializable ;
( 4)尽量降低成员的访问权限。
迪米特法则作用:降低类之间的耦合。
迪米特法则的负面影响:
利用迪米特法则虽然可以采用“中介”实现当前类与非直接的类通信,但是过分的使用迪米特法则,会产生大量中介和传递类,导致系统复杂度变大。
所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。
标签:七个,父类,原则,对象,子类,接口,抽象,设计模式 来源: https://blog.csdn.net/weixin_45847765/article/details/121731758