Java设计模式

来源:互联网 发布:淘宝的华歌尔是正品吗 编辑:程序博客网 时间:2024/05/18 20:51

一、简介

设计模式(Design Pattern)是一种模式,一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

二、六大原则

这里写图片描述
图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。

2.1 设计模式之开闭原则

2.1.1 涵义

开闭原则(Open Closed Principle, OCP)是指“软件实体应该对扩展开放,对修改关闭”,也就是在不修改源码的情况下,可以添加新的功能。

“对扩展开放”意味着对模块的行为是可以扩展的,也就是对于组件功能的扩展是开放的。“对修改关闭”对模块行为扩展时不必改动模块的源代码或二进制代码。简言之就是可以根据需要添加新的类,但不要修改原有的类。

2.1.2 为何要遵循开闭原则

因为开闭原则是一切设计原则的基础,它是判断面向对象设计是否正确的最基本的原则之一。如果一个软件遵循了开闭原则,那么这个软件至少有以下优点

  • 可扩展程度高,非常灵活。无论是在软件开发中,还是在软件开发完成以后,我们都可以在软件中进行扩展,加入新功能,这样软件可以随着不断增加新模块来满足不断变化的新需求。
  • 可维护性强,不用修改原代码。因此变化的软件系统有一定的稳定性和延续性。

实现开闭原则的核心在于“用抽象构建框架,用实现扩展细节”。首先需要区分哪些部分是变化的,哪些是不变的。对于不变的这部分,我们可以把不变的部分加以抽象成不变的接口。对于变化的部分,我们可以进行评估和分类,每一个可变的因素都单独进行封装。

即便如此,由于需求的变化,设计师在设计阶段要整理清楚所有的系统行为,这本身是不现实的。因此,我们只能在某些组件、某种程度上符合开闭原则的要求。

2.2 单一职责原则

单一职责原则(single responsibility principle, SRP)是指“就一个类而言,应该仅有一个引起它变化的原因”。我们可以做以下分析:

  • 防止相同类型的职责,分离到不同的类中。即我们需要提高代码的可重用性。
  • 同一个类无需编制多余的职责。

单一职责原则优点:

  • 有助于清晰地理清设计和编码的思路。
  • 有助于简化维护、编码、测试的流程。
  • 复杂问题简单化,有助于代码的重用。
  • 职责之间消除耦合后,有利于系统的扩展。

说到单一职责原则,很多人都会不屑一顾。因为它太简单了。稍有经验的程序员即使从来没有读过设计模式、从来没有听说过单一职责原则,在设计软件时也会自觉的遵守这一重要原则,因为这是常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2

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

2.3 里氏代换原则

里氏代换原则(Liskov Substitution Principle,LSP)是由Barbara Liskov于1988年提出的,它完整的解读是“若对每个类型S的对象o1,都存在一个类型T的对象o2,使得在所有在针对编写的程序P中,用o1替换o2后,程序P的所有功能不变,则S是T的子类”即所有引用基类的地方必须能透明地使用其子类的对象。

目前,继承是面向对象思想中的一个重要特点。它具有很多优点:

  • 减少重复编码,从而实现代码的可重用性。
  • 子类和基类可以相似,也可以有各自的不同之处。
  • 基类,可以提高代码的开放性。

但是,当父类的属性或方法变动时,其子类也要随之修改。如果没有一个科学的规范,则结果会导致大量的代码重构。

继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。

里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:

  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

2.4 依赖倒置原则

依赖倒置原则(Dependence Inversion Principle,DIP)有两种定义:

  • 高层模块不应该依赖低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。简言之,就是我们在设计系统时需要运用抽象来分析,而不必开始就关注细节。
  • 要针对接口编程,不要针对实现编程。简言之,我们可以通过接口和抽象类进行各种变量、参数、方法等的声明,并且禁止实现类去做以上声明。

依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在Java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

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

2.5 接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP)有以下两个定义:

  • 不应该强迫客户依赖于他们不用的方法
  • 一个类对另一个类依赖性应该建立在最小的接口上

它们都是在说定义接口时要准确,不要创建多余的方法。比如将我们的手机构建成一个接口,如下图:
这里写图片描述
此时,我的手机和他的手机要调用手机接口,则会显示接口的所有方法。但是此时我的手机和他的手机用处不同,则需要将接口重新规划。我的手机用于上网和玩游戏,他的手机用于发信息和通话:
这里写图片描述

说到这里,很多人会觉的接口隔离原则跟之前的单一职责原则很相似,其实不然。其一,单一职责原则原注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。

采用接口隔离原则对接口进行约束时,要注意以下几点:

  • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
  • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

2.6 迪米特法则

迪米特法则(最少知道原则)(Demeter Principle),它是指一个对象应当对其他对象有尽可能少的了解,不必与不相识的人直接联系。

自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。

首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部

使用迪米特法则的好处:

  • 迪米特法则有利于降低类之间的耦合度。由于类和类之间去除了依赖关系,则各个软件功能模块之间相互独立。
  • 遵循迪米特法则进行设计时,如果需要系统扩展,则更加符合开闭原则对修改关闭的要求。
  • 使用迪米特法则将系统的内部数据与实现细节隐藏,从而是各个功能子模块远离耦合,最终达到提高代码的重用性和可维护性。
原创粉丝点击