文章内容
一、什么是访问者模式
访问者模式,将作用于某种数据结构中的各元素的操作分离出来,封装成独立的类,使其在不改变数据结构的前提下,可以添加作用于这些元素的新的操作,为数据结构中的每个元素,提供多种访问方式。
访问者模式,属于对象行为型模式。
二、访问者模式UML类图
三、访问者模式角色
- 抽象访问者角色(Vistor): 接口或抽象类,它定义了对每一个元素访问的行为,它的参数就是可以访问的元素,它的方法数理论上来说与元素个数一致。
- 具体访问者角色(ConcreteVistor): 具体的访问者实现类,它需要给出对每一个元素类访问时所产生的具体实现。
- 抽象元素角色(Element): 接口或抽象类,它定义了一个接受访问者参数的方法,表明每一个元素都可以被访问者访问。
- 具体元素角色(ConcreteElement): 具体的元素类,提供了对抽象元素类的实现,通常情况下是使用访问者提供的访问该元素类的方法。
- 对象结构角色(ObjectStructure):是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
四、访问者模式优缺点
优点:
- 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
- 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
- 灵活性好。将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
- 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
缺点:
- 违背了开闭原则。每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作。
- 破坏封装。具体元素对访问者公布细节,这破坏了对象的封装性。
- 违反了依赖倒置原则。依赖了具体类,而没有依赖抽象类。
五、访问者模式demo示例
1、Demo需求
通过访问者模式:实现参赛者参加运动会,并可以查看比赛成绩。比赛项目有跳高、跳远、铅球和标枪,参赛者有孙悟空、沙悟净、猪八戒和唐僧。
2、抽象类定义
/**
* @Description: 抽象访问者角色:参赛者类
**/ public abstract class Contestant {
protected String name;
public Contestant(String name) {
this.name = name;
}
/**
* 参加跳远比赛
*
* @param longJump
*/ public abstract void joinLongJump(LongJump longJump);
/**
* 參加投掷标枪比赛
*
* @param javelin
*/ public abstract void joinJavelin(Javelin javelin);
/**
* 参加跳高比赛
*
* @param highJump
*/ public abstract void joinHighJump(HighJump highJump);
/**
* 参加投掷铅球比赛
*
* @param shot
*/ public abstract void joinShot(Shot shot);
}
/**
* @Description: 抽象元素角色:体育运动类
**/ public abstract class Sports {
// 比赛项目名称
protected String name;
public Sports(String name) {
this.name = name;
}
/**
* 获取比赛成绩
*
* @param contestant
* @return
*/ public abstract void showScore(Contestant contestant);
}
3、实现类定义
/**
* @Description: 具体访问者角色: 沙悟净类
**/ public class ShaWuJing extends Contestant {
public ShaWuJing(String name) {
super(name);
}
/**
* 沙悟净参加跳远比赛成绩
*
* @param longJump
*/ @Override
public void joinLongJump(LongJump longJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, longJump.name));
}
/**
* 沙悟净参加投掷标枪成绩
*
* @param javelin
*/ @Override
public void joinJavelin(Javelin javelin) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, javelin.name));
}
/**
* 沙悟净参加跳高比赛成绩
*
* @param highJump
*/ @Override
public void joinHighJump(HighJump highJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, highJump.name));
}
/**
* 沙悟净参加投掷铅球成绩
*
* @param shot
*/ @Override
public void joinShot(Shot shot) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, shot.name));
}
}
/**
* @Description: 具体访问者角色: 孙悟空类
**/ public class SunWuKong extends Contestant {
public SunWuKong(String name) {
super(name);
}
/**
* 孙悟空参加跳远比赛成绩
*
* @param longJump
*/ @Override
public void joinLongJump(LongJump longJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, longJump.name));
}
/**
* 孙悟空参加投掷标枪成绩
*
* @param javelin
*/ @Override
public void joinJavelin(Javelin javelin) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, javelin.name));
}
/**
* 孙悟空参加跳高比赛成绩
*
* @param highJump
*/ @Override
public void joinHighJump(HighJump highJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, highJump.name));
}
/**
* 孙悟空参加投掷铅球成绩
*
* @param shot
*/ @Override
public void joinShot(Shot shot) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, shot.name));
}
}
/**
* @Description: 具体访问者角色: 猪八戒类
**/ public class ZhuBaJie extends Contestant {
public ZhuBaJie(String name) {
super(name);
}
/**
* 猪八戒参加跳远比赛成绩
*
* @param longJump
*/ @Override
public void joinLongJump(LongJump longJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, longJump.name));
}
/**
* 猪八戒参加投掷标枪成绩
*
* @param javelin
*/ @Override
public void joinJavelin(Javelin javelin) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, javelin.name));
}
/**
* 猪八戒参加跳高比赛成绩
*
* @param highJump
*/ @Override
public void joinHighJump(HighJump highJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, highJump.name));
}
/**
* 猪八戒参加投掷铅球成绩
*
* @param shot
*/ @Override
public void joinShot(Shot shot) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, shot.name));
}
}
/**
* @Description: 具体访问者角色: 唐僧类
**/ public class TangSeng extends Contestant {
public TangSeng(String name) {
super(name);
}
/**
* 唐僧参加跳远比赛成绩
*
* @param longJump
*/ @Override
public void joinLongJump(LongJump longJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, longJump.name));
}
/**
* 唐僧参加投掷标枪成绩
*
* @param javelin
*/ @Override
public void joinJavelin(Javelin javelin) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, javelin.name));
}
/**
* 唐僧参加跳高比赛成绩
*
* @param highJump
*/ @Override
public void joinHighJump(HighJump highJump) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, highJump.name));
}
/**
* 唐僧参加投掷铅球成绩
*
* @param shot
*/ @Override
public void joinShot(Shot shot) {
System.out.println(String.format("%s, 参加了 %s 比赛",name, shot.name));
}
}
/**
* @Description: 具体元素角色: 跳高类
**/ public class HighJump extends Sports {
public HighJump(String name) {
super(name);
}
@Override
public void showScore(Contestant contestant) {
contestant.joinHighJump(this);
double v = new Random().nextInt(8);
System.out.println(contestant.name+", "+name+" 比赛成绩= "+v);
System.out.println("----------------------------------------------");
}
}
/**
* @Description: 具体元素角色:标枪类
**/ public class Javelin extends Sports {
public Javelin(String name) {
super(name);
}
@Override
public void showScore(Contestant contestant) {
contestant.joinJavelin(this);
double v = new Random().nextInt(20);
System.out.println(contestant.name+", "+name+" 比赛成绩= "+v);
System.out.println("----------------------------------------------");
}
}
/**
* @Description: 具体元素角色:跳远类
**/ public class LongJump extends Sports {
public LongJump(String name) {
super(name);
}
@Override
public void showScore(Contestant contestant) {
contestant.joinLongJump(this);
double v = new Random().nextInt(10);
System.out.println(contestant.name+", "+name+" 比赛成绩= "+v);
System.out.println("----------------------------------------------");
}
}
/**
* @Description: 具体元素角色: 铅球类
**/ public class Shot extends Sports {
public Shot(String name) {
super(name);
}
@Override
public void showScore(Contestant contestant) {
contestant.joinShot(this);
double v = new Random().nextInt(15);
System.out.println(contestant.name+", "+name+" 比赛成绩= "+v);
System.out.println("----------------------------------------------");
}
}
/**
* @Description: 对象结构角色: 操场
**/ public class SportsGround {
// 比赛项目集合列表
private List<Sports> sportsList = new ArrayList<>();
/**
* 参赛者报名加入比赛
*
* @param sports
*/ public void add(Sports sports){
sportsList.add(sports);
}
/**
* 参赛者退出比赛
*
* @param sports
*/ public void remove(Sports sports){
sportsList.remove(sports);
}
/**
* 查看参赛者成绩
*
* @param contestant
*/ public void showScore(Contestant contestant){
sportsList.forEach(s->{
s.showScore(contestant);
});
}
}
4、测试
/**
* @Description: 访问者模式客户端测试类
**/ public class Client {
public static void main(String[] args) {
// 构建对象结构实例
SportsGround sportsGround = new SportsGround();
// 加入比赛项目
sportsGround.add(new LongJump("跳远"));
sportsGround.add(new HighJump("跳高"));
sportsGround.add(new Javelin("标枪"));
sportsGround.add(new Shot("铅球"));
// 孙悟空参加比赛,看看比赛成绩
sportsGround.showScore(new SunWuKong("孙悟空"));
System.out.println("==================================");
// 猪八戒参加比赛,看看比赛成绩
sportsGround.showScore(new SunWuKong("猪八戒"));
System.out.println("==================================");
// 沙悟净参加比赛,看看比赛成绩
sportsGround.showScore(new SunWuKong("沙悟净"));
System.out.println("==================================");
// 唐僧参加比赛,看看比赛成绩
sportsGround.showScore(new SunWuKong("唐僧"));
}
}
控制台日志:
孙悟空, 参加了跳远比赛
孙悟空, 跳远比赛成绩= 1.0
----------------------------------------------
孙悟空, 参加了跳高比赛
孙悟空, 跳高比赛成绩= 0.0
----------------------------------------------
孙悟空, 参加了标枪比赛
孙悟空, 标枪比赛成绩= 4.0
----------------------------------------------
孙悟空, 参加了铅球比赛
孙悟空, 铅球比赛成绩= 5.0
----------------------------------------------
==================================
猪八戒, 参加了跳远比赛
猪八戒, 跳远比赛成绩= 1.0
----------------------------------------------
猪八戒, 参加了跳高比赛
猪八戒, 跳高比赛成绩= 1.0
----------------------------------------------
猪八戒, 参加了标枪比赛
猪八戒, 标枪比赛成绩= 5.0
----------------------------------------------
猪八戒, 参加了铅球比赛
猪八戒, 铅球比赛成绩= 5.0
----------------------------------------------
==================================
沙悟净, 参加了跳远比赛
沙悟净, 跳远比赛成绩= 8.0
----------------------------------------------
沙悟净, 参加了跳高比赛
沙悟净, 跳高比赛成绩= 7.0
----------------------------------------------
沙悟净, 参加了标枪比赛
沙悟净, 标枪比赛成绩= 12.0
----------------------------------------------
沙悟净, 参加了铅球比赛
沙悟净, 铅球比赛成绩= 3.0
----------------------------------------------
==================================
唐僧, 参加了跳远比赛
唐僧, 跳远比赛成绩= 6.0
----------------------------------------------
唐僧, 参加了跳高比赛
唐僧, 跳高比赛成绩= 4.0
----------------------------------------------
唐僧, 参加了标枪比赛
唐僧, 标枪比赛成绩= 16.0
----------------------------------------------
唐僧, 参加了铅球比赛
唐僧, 铅球比赛成绩= 6.0
----------------------------------------------