设计模式(二) 面向对象设计原则

来源:互联网 发布:淘宝复核认证在哪里 编辑:程序博客网 时间:2024/04/30 03:50

单一职责原则 SRP:最简单的面向对象设计原则,用于控制类的粒度大小

一个类只负责一个功能领域的相应职责,或者说,就一个类而言,只有一个能引起它变化的原因。

比如,设计一个CRM(客户关系管理)系统中的客户信息图形统计模块CustomerDataChart,该类的成员方法既包含图表的创建显示,也包含查询客户信息,以及连接数据库。

事实上图表处理是一个独立功能,数据库连接操作也是独立的数据库应用功能,查询客户信息也可以独立成数据库访问操作功能,可以重构成3个部分:

CustomerDataChart类负责图表的创建显示,并有一个成员方法,使用到数据库访问操作类DAO的接口,DAO负责了查询客户信息,同样通过关联关系,使用了DBUtil类的连接数据库等方法。


开闭原则 OCP: 可复用设计的基础之一。

一个软件实体应对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

可以应用到一个软件模块、一个由多各类组成的局部结构或者独立的类。

软件的需求会随着时间的推移而改变。当系统需要面对新的需求,应尽量保证系统的设计框架是稳定的。如果符合OCP,则很方便对系统进行扩展,无需修改现有代码(适应性、灵活性、稳定性和延续性)

为满足OCP,需要对系统进行抽象化设计。可以为系统定义相对稳定的抽象层,将不同的的实现行为转移至具体的实现层中完成。比如接口、抽象类等机制。


里氏代换原则 LSP:

所有引用基类的地方必须能透明地使用其子类的对象。

这表明,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来不成立。

比如我喜欢动物,那我一定喜欢狗,成立,因为狗是动物的子类;但是我喜欢狗,但不能断定我喜欢动物,因为我可能不喜欢老鼠,即使老鼠也是动物。

基于LSP,程序之中应尽量使用基类类型对象来对对象进行定义,在运行时在确定其子类类型,用子类对象替换基类对象。另外,应该将父类设计为抽象类或者接口,让子类继承或者实现父类接口。运行时子类实例替换父类实例,扩展系统无需修改原有子类的代码,增加新的功能通过增加一个新的子类来实现。


依赖倒转原则 DIP

抽象不应该依赖于细节,细节应该依赖于抽象。换言之,要针对接口编程,而不是针对实线编程。

具体来说,使用接口和抽象类来进行变量类型声明、参数类型声明、方法返回类型声明、以及数据类型的转换等,不要使用具体类来做这些事情。

一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

在实现DIP时,需要针对抽象层编程,而将具体类的对象通过依赖注入的方式注入到其他对象中。三种注入方式:构造注入、设值注入、接口注入。

这些方法在定义时使用的是抽象类型,但在运行时再传入具体类型的对象,由子类对象覆盖父类对象。


接口隔离原则 ISP 

使用多个专门的接口,而不使用单一的总接口,客户端不应该依赖那些它不需要的接口。

当接口太大时,应该将其分割成更细小具体的接口。使用该接口的客户端只需要知道与之相关的方法即可。

接口具有角色的相对独立性。为了使接口的职责单一,需要将大接口的方法根据其职责不同分别放在不同的小接口中,以确保每个接口使用起来都较为方便,并都承担某一单一角色。

接口应当尽量细化,同时确保接口中的方法尽量少,每个接口中都只包含一个客户端所需的方法即可。(“定制服务”)一般而言,接口中仅包含为某一类用户定制的方法即可。


合成复用原则

尽量使用对象组合,而不是继承来实现复用的目的。

实现复用时,多用关联(组合或聚合),少用继承。

也就是在一个新的对象里通过关联关系(包括组合、聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过调用已有对象的方法达到复用功能的目的。

复用时尽量使用组合/聚合关系,少用继承。

面向对象设计中,可以通过两种方法在不同的环境中复用已有的设计和实现。即通过组合/组合关系,或者通过继承,但应首先考虑使用组合/聚合,组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,要严格遵循里氏代换原则,滥用继承会增加系统复杂度以及维护的难度。 高内聚低耦合

继承复用会破坏系统的封装性,又称“白箱复用”,基类发生变化子类的实现也不得不发生改变,从基类继承而来的实线是静态的,不可能在运行时发生改变,欠灵活性;并且只能在类没有声明为不可继承的情况下使用。

组合/聚合关系保持原有的可见性,“黑箱复用”,耦合度较低,成员对象的变化对新对象的影响不大,在新对象中可以更具实际需要有选择性地调用成员对象的操作,合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。

一般,如果两个类是 Has-A 关系,应使用组合或聚合,如果是Is-A可以使用继承。


迪米特法则 LoD

一个软件实体应当尽可能少地与其他实体发生作用。

如果满足LoD,那么当系统某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易。

限制实体之间通信的宽度和深度,降低系统的耦合度,使类与类之间保持松散的耦合关系。

(1)不要和“陌生人”说话,只和你的直接朋友通信。朋友:当前对象本身(this);以参数形式传入当前对象方法的对象;当前对象的成员对象;如果当前对象的成员对象是一个集合,那么集合中的元素也是朋友;当前对象所创建的对象;


如果两个对象之间不必直接通信,可以通过第三者转发这个调用。引入第三者降低对象之间的耦合度。

(1)在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,越有利于复用。这样的类一旦被修改,不会对关联的类造成太大的波及。

(2)降低成员变量和成员函数的访问权限

(3)尽可能将类设计成不变类

(4)在对其他类的引用上,对象之间的引用降到最低。


0 0