Java的11种设计模式学习

14次阅读

共计 4023 个字符,预计需要花费 11 分钟才能阅读完成。

一:设计模式是最重要的课程之一,堪称软件界的九阳真经, 设计模式是一大套被反复使用,多数人知晓的,经过分类编目的,代码总结,使用设计模式是为了可重用代码. 让代码更容易被他人理解,保证代码可靠性。

二:学习设计模式最常见的理由是因为我们可以借其:

1. 复用解决方案 —- 避免重蹈前人的覆辙,从学习他人的经验中获益,用不着为那些总是会重复出现的问题再次设计解决方案.

2. 确定通用术语 —– 设计模式在项目的分析和设计阶段提供了共同的基准点.

三:设计模式中一般都遵循这们的原则:

1. 按接口编程.

2. 尽量使用组合代替继承.

3. 找出变化并封装。

下面是具体的设计模式:

l 工厂模式 <Factoty>

定义:用一个方法代替构造器和 new 关键字,把对象的创建隐藏起来.

解决的问题:用来解决一个一个生成方式过多,容易产生变动,或者是父类和了类之间容易替换的地方。工厂模式就相当于创建实例对象的 new,工厂模式使得我们不必关心具体类是怎么实现的,它提供了程序的拓展性,降低了耦合度.

l 单例模式 <Singleton>

定义:一个类在 java 虚拟机中只能创建一个对象。

单例模式的构建有两种方式:

a: 懒汉式: 指全局的单例实例在第一次被使用时创建。

b: 饿汉式: 指全局的单例实例在类加载的时候创建。

单例模式必须要满足以下四个条件:

1. 单例类必须要有一个私有的构造器.

2. 单例类的实例必须为全局的,且用 private static 修饰.

3. 必须提供一个对外开放的创建对象的方法。

4. 对放的方法必须是用公共,静态且同步的方法.public synchronized static xxx();

用到的地方:当一个类的实例,有且只能创建一个时用到。

l 门面模式 <Facade>

定义:定义一个高层接口,把所有子类的交互,通过这个接口来实现,这个接口集成了所有子系统的类。

< 书面说法:为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 >

解决问题:子接口繁多,调用复杂,内部交互地方比较多。

l 策略模式 <Strategy>

定义:定义一系列的算法,将它们封装起来,使得它们可以替换,使用策略模式使得算法可独立于使用它的客户而变化。

解决问题:某个具体的解决方法有很多种可选实现。

适用情形:

a: 如果在一个系统里面有许多类,它们之间的区别在于它们的行为,那么使用策略模式可以动态的让一个对象在许多行为中选择一个种行为。

b: 一个系统需要动态地在几种算法中选择一种,那么这些算法可以包装到一个个具体算法类里面,而这些算法都是一个抽象算法类的子类,换言之,这些具本算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体类算法,并只持有一个数据类型是抽象算法类的对象.

l 模板模式 <Template>

定义:在操作中定义一系列骨架,将一些操作的步骤延迟到子类中。父类定义流程,子类具体实现。

解决问题:主要是解决子类之间代码或流程的重复问题。

优点:

1:利用了继承的方法,在基类中定义了算法的框架,并将算法的可变部他声明为可重写的,由具体子类使用,这样可以利用同样的框架,完成不同的功能,它的效率比策略模式高,并且比较简单。

2:使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板模式的结构:

1>:AbstractClass 类,定义了一到多的抽象方法,以供具体子类来实现它们,而且还要实现这一个模板方法,来定义一个算法骨架,该模板方法不仅调用前面的抽象方法,也可以调用其他的操作,只要能完成自身的使命。

2>:ConcreteClass(具体类):实现父类中的抽象方法以完成算法中与特定子类相关的步骤。

适用情况:

1>:一次性实现一个算法的不变的部分,并将可变的行为留给子类实现。

2>:各子类中的公共行为应被提取出来集中到一个公共父类中,以避免代码重复,其实这可以说是一种好的编码习惯。

3>:控制子类扩展,模板方法只在特定点调用操作,这样就只允许这些点进行扩展。

如果你不愿子类修改你的模板方法定义的框架,你可以采用两种方式来做:

1>:将 API 中不体现出你的模板方法。

2>:将你的模板方法置为 final 就可以了。

l 适配器模式 <Adapter>(将不兼容的变得兼容)

生活中的实例:变压器。

定义:将一个类的接口转换成客户希望的另一个接口,这样使得两个原本不兼容的接口可以在一起正常工作。

例子:DBUtil 的 QueryRun 类的 Update 方法, 如果提供的是两个参数, 想将它转换成三个参数, 这时候就用到了适配器模式, 适配器模式用两种, 一是类适配器, 二是对象适配器,但考虑到设计模式中遵循的条件:

a: 按接口编程;

b: 尽量使用组合代替继承.

c: 找出变化将它们封装.

所以这个时候我们用对象适配器.

解决的问题:已经存在类似功能的类或接口,但方法签名不一样。

l 观察者模式 <Observer>(1:依赖;2:一对多)

定义:定义对一个对象间的一种一对多的关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

< 提供给关联对象一种同步通信的手段,使某个对象与依赖于它的其它对象保持状态同步 >.

解决问题:解决多个对象间相互依赖关系的相互通知。

意图:1:当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。

2:当一个对象必须通知其它对象,而它又不能假定其它对是谁,换言之,你不希望这些对象是紧密耦合的。

优缺点:

1:对象之间可以进行同步通信

2:可以同时通知一到多个关联对象

3:对象之间的关系以松耦合的形式,互下依赖。

l 抽象工厂模式 <AbstractFactory> 实例:衣服,裤子,鞋子它们可以是阿迪的,耐克的。。。。等等。

定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

使用的原因:是由于它能将实现类和它们的生成过程完全分割开来。

用途 :

* 一个系统要独立于它的产品的创建、组合和表示时。

* 一个系统要由多个产品系列中的一个来配置时。

* 当你要强调一系列相关的产品对象的设计以便进行联合使用时。

* 当你提供一个产品类库,而只想显示它们的接口而不是实现。

抽象工厂负责管理子工厂对象,子工厂对象生成某一类具体的产品对象。

l 状态模式 <State>(状态决定行为)

状态模式: 生活中的实例: 红, 绿, 灯.

一: 定义: 不同的状态, 不同的行为; 或者说, 每个状态有着相应的行为.

用通俗的话说: 就是一个状态一个行为, 不同的状态有着不同的行为.

二: 何时使用:

State 模式在实际使用中比较多, 适合 ” 状态的切换 ”.

因为我们经常会使用 If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现, 我们就要联想到是否可以采取 State 模式了.

三: 解决的问题: 逻辑不是很复杂的, 不能解决.它不能解决未知的状态.

解决问题

1) 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。

2) 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。

四: 缺点

每个状态对应一个具体的状态类,使得整体分散,逻辑不太清晰

五: 优点

状态模式的引入免除了代码中复杂而庸长的逻辑判断语句。

而且具体状态角色将具体状态和它对应的行为封装了起来,这使得增加一种新的状态变得简单一些.

l 装饰器模式 <Decorator>: 生活中的实例: 给墙刷油漆.

定义:动态地给一个对象添加一些额外的职责。就增加功能来说,

Decorator 模式相比生成子类更为灵活。

通俗的说: 在不改变一个类的源代码, 不通过继承, 实现, 就能动态的添加一些额外的功能.

解决问题:一个对象需要经常动态增加属性或指责

适用性:

* 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

* 处理那些可以撤消的职责。

* 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。

另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

为什么使用 Decorator?

我们通常可以使用继承来实现功能的拓展, 如果这些需要拓展的功能的种类很繁多, 那么势必生成很多子类, 增加系统的复杂性, 同时, 使用继承实现功能拓展, 我们必须可预见这些拓展功能, 这些功能是编译时就确定了, 是静态的.

使用 Decorator 的理由是: 这些功能需要由用户动态决定加入的方式和时机.Decorator 提供了 ” 即插即用 ” 的方法, 在运行期间决定何时增加何种功能.

如何使用?

举 Adapter 中的打桩示例, 在 Adapter 中有两种类: 方形桩 圆形桩,Adapter 模式展示如何综合使用这两个类, 在 Decorator 模式中, 我们是要在打桩时增加一些额外功能, 比如, 挖坑 在桩上钉木板等, 不关心如何使用两个不相关的类.

优点:

1)提供比继承更多的灵活性

2)使用不同的装饰组合可以创造出不同行为的组合

3)需要的类的数目减少

缺点:

1)灵活性带来比较大的出错性

2)产生更多的对象,给查错带来困难

l 组合模式 <Composite> 例:connection 里有 set,map 再下就是 ArrayListHashMap

例子:合做各种各样的树形菜单。

定义: 将对象以树形结构组织起来, 以达成“部分-整体”的层次结构,

使得客户端对单个对象和组合对象的使用具有一致性.

解决问题: 树形数据结构的方案.

适用性:

* 你想表示对象的部分 - 整体层次结构。

* 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

Composite 模式优缺点及适用情况:

1)优点:使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构, 就简化了客户端代码。

2)缺点: 我觉得 Leaf 类完全不应该来实现 Component,应为它基本只是使用一个显示的作用,不能进行其他的操作如添加、删除等,如果实现 Component 容易产生误操作。
/**

正文完
 0