java设计模式—六大设计原则

一,单一职责原则

一个类只负责一个功能领域中相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

单一职责原则是实现高内聚,低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强分析设计能力和相关实践经验。

扩展:说到单一职责原则,其实很多人不知不觉的都在使用,即使没有学习过设计模式的人,或者没有听说过单一职责原则这个概念的人也会自觉的遵守这个重要原则,因为这是一个常识,比如你去在原有的项目上开发一个新的业务功能的时候,你肯定从新建一个类,来实现一个新的功能,肯定不会基于原有的A功能身上直接写B业务功能,肯定一般都是回写一个新类来实现。在软件编程中,谁也不希望因为修改一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。但是我门经常会出现违背这一原则的情况。因为职责扩散,所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。

比如:类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于某种原因,也许是需求变更了,也许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1,P2,这时如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,分别负责P1、P2两个职责。但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。(这样做的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,在未来可能会扩散为P1,P2,P3,P4……Pn。所以记住,在职责扩散到我们无法控制的程度之前,立刻对代码进行重构。)

二,里氏替换原则

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

里氏替换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的时一个子类对象的话,那么它不一定能够使用基类对象。

里氏替换原则是对“开闭原则”的补充,实现开闭原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。

当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。

继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达这一含义。

继承作为面向对象三大特性之一,再给程序设计带来巨大遍历的同时,也带来弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。

在实际编程中,我们常常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。

三,开闭原则

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

软件实体可以指一个软件模块,一个由多个类组成的局部结构或一个独立的类。抽象化是开闭原则的关键。

任何软甲都需要面临一个很重要的问题,即它们的需求会随时间的推移而发生变化。当软件系统需要面对新的需求时,我们应该尽量保证系统的设计框架是稳定的。如果一个软件设计符合开闭原则,那么可以非常方便地对系统进行扩展,而且在扩展时无须修改现有代码,使得软件系统在拥有适应性和灵活性的同时具备较好的稳定性和延续性。随着软件规模越来越大,软件寿命越来越长,维护成本越来越高,设计满足开闭原则的软件系统也变得越来越重要。

四,依赖倒置原则

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

依赖倒置原则的核心思想是面向接口编程

依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

五,接口隔离原则

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

当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需指导与之相关的方法即可。

每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。

如果把“接口”理解成狭义的特定语言的接口,那么ISP(接口隔离原则)表达的意思是指接口仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。接口应该尽量细化,同时接口中的方法应该尽量少,每个接口中只包含一个客户端所需的方法即可,这种机制也称为“定制服务”。同时我们需要之一控制接口的粒度。

六,迪米特法则(最少知识原则)

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

如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度。迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。

迪米特法则有几种定义形式:不要和陌生人说话,只与你的直接朋友通信等,在迪米特法则中,对于一个对象,其朋友包括以下几类:

(1)当前对象本身

(2)以参数形式传入到当前对象方法中的对象

(3)当前对象的成员对象

(4)如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友

(5)当前对象所创建的对象

迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简而言之,就是通过引用一个合理的第三者来降低现有对象之间耦合度。

在类的划分上,应当尽量创建松散耦合的类,类之间的耦合度越低,就越有利于复合,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及,在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类,在对其他类的引用上,一个对象对其他对象的引用应当降到最低。

通俗的来将,就是一个类对自己依赖的类知道的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。

用抽象构建框架,用实现扩展细节的注意事项而已:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值