浅析Java中的设计模式

1.前言

最近在上软件构造课程的时候讲到了“设计模式”这一概念,合理的设计模式对于编写一个高效、简洁、安全、复用性和可维护性强的程序具有重要意义。

2.分类

首先,设计模式分为三大类:创建型模式,结构型模式和行为类模式,每个模式下又分为几个小类,其中创建型模式主要关注的是一个对象的创建过程,结构型模式主要处理类和对象的组织关系,而行为类模式主要关注和区分不同类和对象之间的互动和责任分配。大体分类如下:

(一)创建型(Creational patterns)

1.工厂方法模式(Factory Method pattern)

(二)结构型(Structural patterns)

2.适配器模式(Adapter)

3.装饰器模式(Decorator)

(三)行为型(Behavioral patterns)

4.策略模式(Strategy)

5.模板模式(Template Method)

6.迭代器模式(Iterator)

7.访客模式(visitor)

3.具体说明

下面将就各种模式做一个具体的说明:

1.工厂方法模式

(1)定义

工厂方法模式又称为“虚拟构造器”,主要是指新建一个工厂类,这个类专门用来生产另一个抽象类或接口中所定义的具体类。

(2)什么时候要用工厂方法

①客户端不知道要创建哪个具体类的实例时

②客户端不想在代码中指明它想创建的类是哪个类时

③要创建具体类的类不想现在就决定,想要留到它的子类中去决定具体选择哪一个类时

(3)具体工作模式

如图,Produt是一个抽象类或者是接口,ProductOne和ProductTwo是具体的实现类,而ConcreteOne和ConcreteTwo就是工厂类,在工厂模式下,客户端可直接调用ConcreteTwo或ConcreteOne中的方法来创建product:

注意工厂类中的方法可以是静态的也可以是实例方法,创建具体产品方法的可以是同一个类中的不同方法,也可以是工厂类接口的两个不同子类中的方法。

(4)优缺点:

优点:消除了避免了代码中盲目的实例化具体对象的行为,而且既然代码针对特定的接口都能工作,那么它对接口下的任意一种实例化类都能够工作,而且满足OCP原则:对扩展的开放,对修改已有代码的封闭。

缺点:但是这样也是有缺点的,如果客户端真的需要这样一个工厂类的话创建这么一个工厂类是可以接受的,但是如果不是,用户也可以选择直接实例化一个具体的产品方法,具体的需求场景见上文的适用场景。

2.适配器模式

(1)定义:将某个类(接口)转换为客户端所期望的形式

(2)具体实现:

简单来说适配器模式就是在一个新的接口的实现中委派之前定义过的类来实现具体的方法,从而达到目的,用户调用新的接口的时候,只知道实现了特定的功能,而不知道是如何实现的。即通过增加一个接口,将已存在的子类封装起来,客户面向接口编程,从而隐藏了子类。具体实现起来如图所示:

所谓“适配器”即将要实现的新的类的方法适配为之前实现过的旧的类的方法的具体实现。

3.装饰器模式

(1)适用条件:当一个类中除了对于共性的需求,还有许多个特性需要组合的时候。

(2)具体分析:

例如,当我们需要一个“时间段集合”概念的类时(如图),我们除了要实现最基本的时间段集合的类和方法,还要考虑到其他问题,例如:各个时间段时间是否允许重合?时间段之间是否允许留白?是否允许多个时间段对应相同名称(标签)?

我们一个最原始的想法便是将其组织为一个继承关系(a),或是将其组织为一个继承数,在子类中在分别组合:

但是这样的弊端也很明显,就是a中子类会得到很多与自己无关的功能,而b中会存在“组合爆炸”的问题,所以最好的方法是将每个子类设计为一个装饰器模式,在分别套用装饰器,来完成功能组合 的目的。

(3)具体做法如下:首先定义一个借口IntervalSet,然后为其编写一个具体的实现类CommonIntervalSet,在这里只实现其最基础的功能,然后编写一个抽象的装饰类IntervalSetDecorator,父类中定义一个IntervalSet的变量作为被委托着,在构造方法中传入被委托者的实例,如图:

然后在下面的具体方法中全部委派这个被委托者来实现最基础的功能:

然后在每个具体的装饰类中都继承这个抽象方法,然后在对应的重写的方法中增强这个方法的实现,例如:

就完成了对具体特性的装饰,然后在我们需要实例化一个需要多种特性组合的IntervalSet时,只需要层层包装构造一个多种实现方式的组合即可,例如当我们需要一个既不能重合,也不能留空,还需要多标签的IntervalSet时,只需要这样构造:

就像一层层地穿衣服一样。

(4)小结

按照我的理解,装饰器模式就是构造了一个又一个“穿衣服机器”,这个穿衣服机器需要一个人作为输入,输出一个穿好了衣服(增加了功能)的人,这就是装饰器中“装饰”二字的含义。

4.策略模式

(1)适用场景

有多种不同的算法来实现同一个任务,但是需要根据客户端的需要来动态地切换算法,而不是固定在代码中。

(2)实现方法

为不同的实现算法构造抽象接口,利用委派,运行时动态传入客户端倾向的算法实例。例如,我们定义了一个功能实现接口,接口下有多个具体的实现类(利用不同算法),客户端在方法调用的时候只规定具体的功能(例如排序),利用接口名作为参数声明,在函数体中再委派这个参数对象来完成功能,所以在客户端中就可以靠传入参数的具体类型来改变所采用的算法(策略)了。

5.模板模式

(1)定义:做事情的步骤一样,但具体方法不同

(2)实现方式:共性的步骤在抽象类中公共实现(final),差异化的步骤在各个子类中实现(在抽象类中声明为abstract方法),与策略模式中采用委派的方式不同,模板模式采用继承和重写来实现,在调用的时候,直接声明抽象类,在实例化一个具体的实现类即可。

6.迭代器模式

(1)定义:(针对容器类)当客户端希望遍历容器(集合)类中的一组对象时,不关心容器的具体类型,也就是说,不管对象被放进哪里,都应该提供同样的遍历方式。它应该具有如下要求:

①隐藏容器类的具体实现细节

②支持使用同一接口的多种遍历策略

③易于更改容器类的类型

④便于程序之间各个部分的通信

(2)具体实现

迭代器结构如下:迭代器由集合类创建,集合类接口中定义这个方法,集合的具体实现课中实现迭代器的创建并维持迭代器的引用,然后迭代器接口中规定迭代器的行为模式,或者称为迭代器的遍历协议(即定义哪些方法),然后在具体的迭代器中实现这个方法。

Java中定义了两种接口:Iterable接口:需要使用迭代器的集合类需要继承它,Iterator接口:具体的迭代器实现类需要继承它。

7.访客模式

(1)定义:对特定类型的Object的特定操作进行visit,在运行时将二者动态绑定到一起,该操作可以灵活更改,而无需更改被visit的类。

(2)具体做法:首先我们开发一个开发一个ADT,然后预留一个accept方法,该方法以后续设计的visitor对象作为参数,再设计一个visitor类,在该类中对ADT进行访问,计算出相关的内容,即可实现不同算法的动态绑定。

(3)与策略模式的区别

那么两个算法都是实现算法的动态绑定,那么它们有什么区别?区别在于,visitor强调是外部定义的某种ADT操作,与该ADT关系不大,故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。而策略模式则强调是对该ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是委派给外部实现罢了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值