前言

2018年已经过去,新的一年工作已经开始,继续总结和学习Java设计模式。

上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern)。本篇则来学习下行为型模式的两个模式,访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern)。

访问者模式

简介

访问者模式(VisitorPattern),顾名思义使用了这个模式后就可以在不修改已有程序结构的前提下,通过添加额外的访问者来完成对已有代码功能的提升,它属于行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
其主要目的是将数据结构与数据操作分离。

访问者模式可以说是设计模式中最难以理解的一个模式,因为相比其它模式而言,它过于”绕“了。但是我们可以通过生活中的一些例子来理解它,比如家里来了客人,客人就是访问者,他可以做一些事情,但是又不能做全部的事情; 又或者说去网吧上网的小明,小明也是访问者,他可以在网吧玩游戏、看视频、听音乐等等,但是不能破坏网吧中的设备等等。按照这么理解,我们大概就可以知道访问者模式主要是做什么了。

访问者模式主要由这五个角色组成,抽象访问者(Visitor)、具体访问者(ConcreteVisitor)、抽象节点(Node)、具体节点(ConcreteNode)和结构对象(ObjectStructure)。

  • 抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
  • 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
  • 抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
  • 具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
  • 结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素。

示例图如下:

这里为了方便理解,我们使用一个简单的示例来加以说明。
图书馆有一台电脑,有两个账户,其中一个是管理员的账户,拥有所有权限,但是设置了密码;另一个账户是不需要密码,但是只能玩游戏和看图片。张三和李四先后使用了这台电脑,那么他们就可以当作是访问者。
那么我们便可以根据这里例子来使用访问者模式进行开发,首先定义一个抽象的访问者,拥有玩游戏和看图片的方法;然后再定义一个抽象节点电脑,接受这个请求。
那么这个抽象类的代码如下:


interface Visitor {
void visit(Games games);
void visit(Photos photos);
} interface Computer {
void accept(Visitor visitor);
}

定义好该抽象类之后,我们需要设计不同的访问者对节点进行不同的处理。并且需要设计具体节点类实现刚刚抽象节点的方法。

那么代码如下:

class ZhangSan implements Visitor {
@Override
public void visit(Games games) {
games.play();
} @Override
public void visit(Photos photos) {
photos.watch();
}
} class LiSi implements Visitor {
@Override
public void visit(Games games) {
games.play();
}
@Override
public void visit(Photos photos) {
photos.watch();
}
} class Games implements Computer {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
} public void play() {
System.out.println("play lol");
}
} class Photos implements Computer {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
} public void watch() {
System.out.println("watch scenery photo");
}
}

最后我们还需要定义一个结构对象角色,提供一个的接口并允许该访问者进行访问,它可以对这些角色进行增加、修改或删除等操作和遍历。
代码如下:

class ObjectStructure {

    private List<Computer> computers = new ArrayList<Computer>();

    public void action(Visitor visitor) {
computers.forEach(c -> {
c.accept(visitor);
});
}
public void add(Computer computer) {
computers.add(computer);
}
}

编写好之后,那么我们来进行测试。
测试代码如下:


public static void main(String[] args) {
// 创建一个结构对象
ObjectStructure os = new ObjectStructure();
// 给结构增加一个节点
os.add(new Games());
// 给结构增加一个节点
os.add(new Photos());
// 创建一个访问者
Visitor visitor = new ZhangSan();
os.action(visitor); }

输出结果:

play lol
watch scenery photo

访问者模式优点:

扩展性好,可以在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能;
符合单一职责原则,通过访问者将无关的行为分离,使职责单一;

访问者模式缺点:

违反了迪米特原则,因为具体元素对访问者公布细节;
违反了依赖倒置原则,依赖了具体类,没有依赖抽象;
对象结构变化困难,若对象结构发生了改变,访问者的接口和访问者的实现也都要发生相应的改变;

使用场景:

对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作;
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

中介者模式

简介

中介者模式(Mediator Pattern),定义了一个中介对象来封装一系列对象之间的交互关系。中介者使各个对象之间不需要显式地相互引用,从而使耦合性降低,而且可以独立地改变它们之间的交互行为,属于行为型模式。
其主要的目的是用来降低多个对象和类之间的通信复杂性。

简单的来说就是提供一个平台。比如生活中我们经常用到的聊天软件QQ、微信群,或者是上网购物的网站淘宝、京东,又或者是房产中介。但是无论是QQ群,还是房产中介,他们都是充当一个中间平台的作用,我们可以直接通过这个平台得到我们想要的信息,避免了独自获取花费的成本。

中介者模式主要由这四个角色组成, 抽象中介者(Mediator)、具体中介者(ConcreteMediator)、 抽象同事类(Colleague)和具体同事类(ConcreteColleague) 。

  • 抽象中介者(Mediator): 定义了同事对象到中介者对象之间的接口。
  • 具体中介者(ConcreteMediator): 实现抽象中介者的方法,它需要知道所有的具体同事类,同时需要从具体的同事类那里接收信息,并且向具体的同事类发送信息。
  • 抽象同事类(Colleague): 定义了中介者对象的接口,它只知道中介者而不知道其他的同事对象。
  • 具体同事类(ConcreteColleague) : 每个具体同事类都只需要知道自己的行为即可,但是他们都需要认识中介者。

示例图如下:

这里为了方便理解,我们使用一个简单的示例来加以说明。
xuwujing创建了一个Java的QQ群,并邀请了很多人进来,其中张三也加进来了,进群之后,大家开始互相打招呼进行交流。。。
那么我们便可以根据这个简单的例子来使用中介者模式进行开发。
首先依旧定义一个抽象的中介者,就是QQ群,可以进行交流;然后再定义一个抽象的同事类,可以谈话。
那么这个抽象类的代码如下:


interface QQqun {
void exchange(Person person,String message);
} abstract class Person{
protected String name;
protected QQqun qun;
Person(String name,QQqun qun){
this.name = name;
this.qun = qun;
}
}

定义好该抽象类之后,我们再来定义具体的同事类,也就是xuwujing和张三,可以进行交流。

那么代码如下:

class ZhangSan extends Person{

   ZhangSan(String name, QQqun qun) {
super(name, qun);
} void exchange(String message){
qun.exchange(this,message);
} void talk(String message){
System.out.println(name +"说:" + message);
}
} class XuWuJing extends Person{ XuWuJing(String name, QQqun qun) {
super(name, qun);
} void exchange(String message){
qun.exchange(this,message);
} void talk(String message){
System.out.println(name +"回应:" + message);
}
}

最后再来定义具体中介者对象,这个QQ群的具体实现。
代码如下:

class JavaQQqun implements QQqun{
private ZhangSan zs;
private XuWuJing xwj; public ZhangSan getZs() {
return zs;
} public void setZs(ZhangSan zs) {
this.zs = zs;
} public XuWuJing getXwj() {
return xwj;
} public void setXwj(XuWuJing xwj) {
this.xwj = xwj;
} @Override
public void exchange(Person person, String message) {
if(zs.equals(person)){
zs.talk(message);
}else if(xwj.equals(person)){
xwj.talk(message);
}
}
}

最后再来进行测试,定义好交流平台以及需要交流的人员。
那么测试代码如下:


public static void main(String[] args) {
JavaQQqun jq = new JavaQQqun();
ZhangSan zs = new ZhangSan("张三", jq);
XuWuJing xwj = new XuWuJing("xuwujing", jq);
jq.setZs(zs);
jq.setXwj(xwj);
zs.talk("大家好!我是张三!");;
xwj.talk("欢迎你!张三!"); }

输出结果:

张三说:大家好!我是张三
xuwujing回应:欢迎你!张三!

中介者模式优点:

灵活性高,因为将同事类进行了解耦,使其不必有关联性;
降低了类的复杂度,将一对多转化成了一对一;

中介者模式缺点:

中介者使用过多,会使系统变得复杂难以维护;

使用场景:

通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

注意事项:

若不明确各个类的职责,那么就不要进行使用!

和外观模式、代理模式比较

中介者模式和外观模式、代理模式比较类似,但是又有不同。
和外观模式比较,中介者模式中,同事类必须依赖与中介者,中介者也知道同事类;但是外观模式中,子系统是不需要知道外观类的存在,并且子系统是可以脱离外观模式的。
和代理模式,代理模式的核心就是代理作用,主要还是对原先的类进行扩展或增加控制,比如进行权限控制;而中介者模式主要目的是为了减少对象之前的耦合,也就是同事类直接相互独立,互不影响。

Java设计模式之十 ---- 访问者模式和中介者模式的更多相关文章

  1. Java进阶篇设计模式之十 ---- 访问者模式和中介者模式

    前言 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern).本篇则来学习下行为型模式的两个模式,访问者模式(Visito ...

  2. Java设计模式(十二) 策略模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...

  3. 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)

    设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...

  4. Java 设计模式系列(二二)责任链模式

    Java 设计模式系列(二二)责任链模式 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求 ...

  5. 【设计模式】 模式PK:门面模式VS中介者模式

    1.概述 门面模式为复杂的子系统提供一个统一的访问界面,它定义的是一个高层接口,该接口使得子系统更加容易使用,避免外部模块深入到子系统内部而产生与子系统内部细节耦合的问题.中介者模式使用一个中介对象来 ...

  6. Java设计模式(二十一):职责链模式

    职责链模式(Chain Of Responsibility Pattern) 职责链模式(Chain Of Responsibility Pattern):属于对象的行为模式.使多个对象都有机会处理请 ...

  7. 轻松掌握:JavaScript代理模式、中介者模式

    代理模式.中介者模式 代理模式 在面向对象设计中,有一个单一职责原则,指就一个类(对象.函数)而言,应该仅有一个引起它变化的原因.如果一个对象承担了过多的职责,就意味着它将变得巨大,引起它变化的原因就 ...

  8. 重学 Java 设计模式:实战访问者模式「模拟家长与校长,对学生和老师的不同视角信息的访问场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 能力,是你前行的最大保障 年龄会不断的增长,但是什么才能让你不 ...

  9. 设计模式 ( 十六 ): Mediator中介者模式 -- 行为型

    1.概述 在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责,即将行为分布到各个对象中. 对于一个模块或者系统,可能由很多对象构成,而且这些对象 ...

随机推荐

  1. zmq Poller

    1.注册socket到poller中 poller = zmq.Poller() poller.register(frontend, zmq.POLLIN) # receive worker mess ...

  2. Jenkins CLI 命令详解

    笔者在前文<通过 CLI 管理 Jenkins Server>中介绍了如何通过 SSH 或客户端命令行的方式管理 Jenkins Server,限于篇幅,前文主要的目的是介绍连接 Jenk ...

  3. 学习html5的网站

    http://www.html5cn.org/ http://www.html5china.com/ http://www.mhtml5.com/

  4. thinkphp通用控制器

    <?php namespace 目录\Controller; class TypeController extends Controller { public function add() { ...

  5. Jenkins持续集成学习-Windows环境进行.Net开发1

    目录 Jenkins持续集成学习-Windows环境进行.Net开发 目录 前言 目标 使用Jenkins 安装 添加.net环境配置 部署 结语 参考文档 Jenkins持续集成学习-Windows ...

  6. 2017ACM/ICPC亚洲区沈阳站(部分解题报告)

    HDU 6225 Little Boxes 题意 计算四个整数的和 解题思路 使用Java大整数 import java.math.BigInteger; import java.util.Scann ...

  7. SpringBoot入门之集成Druid

    Druid:为监控而生的数据库连接池.这篇先了解下它的简单使用,下篇尝试用它做多数据源配置.主要参考:https://github.com/alibaba/druid/wiki/常见问题 https: ...

  8. js串口通信 调用MSCOMM32控件 链接电子秤(完整版实现方案)

    硬件环境:RS232转USB串口线*1 电子秤*1(本人采用G&G E600Y-C型号称重仪) 电子秤原装RS232数据线*1 计算机*1 软件环境:RS232转USB串口线驱动(这个可以在串 ...

  9. Asp.Net4.5 mvc4(二) 页面创建与讲解

    一.Contorl 通过目录结构我们可以看到contorllers类的命名方式 命名规则:前缀+Controller. 在看看contorller中的action方法 using System; us ...

  10. 所生成项目的处理器架构“MSIL”与引用“Microsoft.AspNet.Scaffolding.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=x86”的处理器架构“x86”不匹配。

    生成成功后: 3>C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(1820,5): ...