设计模式——访问者模式

访问者模式

定义

封装一些的对于某种数据结构中的各元素的操作,它可以在不改变数据的前提下定义作用于这些元素的新的操作

访问者模式(Visitor pattern)是相对简单的模式,也可以作为迭代器模式的补充

优缺点、应用场景

优点

  1. 符合单一职责原则。具体角色负责数据的存储,而访问者对象Visitor负责报表的展示,职责明确区分开来
  2. 优秀的拓展性。由于单一职责,继续增加visitor对数据操作是容易的。
  3. 灵活性非常高。可以对不同的角色做定制化处理。

缺点

  1. 具体角色对访问者公布细节。即visitor关注了具体角色的内部细节,违反了迪米特法则。
  2. 具体角色变更更困难。具体角色属性的变动会导致visitor中对应角色的逻辑变更。
  3. 违背了依赖倒置原则。visitor依赖的是具体的角色,而不是抽象,破坏了依赖倒置原则。在面向对象编程中,直接操作具体角色会造成拓展困难。

应用场景

  1. 一个对象结构包含很多类对象,它们有不同的接口,又需要对这些对象实施一些依赖于其具体类的操作。
  2. 需要对一个对象结构中的对象进行很多不同并且不相关的操作。

模拟场景

打印报表。还原在Van的地♂牢中的场景

非访问者模式

演员的抽象和实现

/**
 * 我们都是演员 抽象类
 */
public abstract class Actors {
	public final static int SLAVE = 0;
	public final static int MASTER = 1;

	private String name;
	private int power;
	private int position;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPower() {
		return power;
	}

	public void setPower(int power) {
		this.power = power;
	}

	public int getPosition() {
		return position;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	/**
	 * 打印演员的信息
	 */
	public void report() {
		String info = "姓名:" + this.name + "\t";
		info += "身份:" + (this.position == SLAVE ? "平家boy" : "Dungeon Master") + "\t";
		info += "权力:" + this.power + "\t";
		info += this.getOtherInfo();
		System.out.println(info);
	}

	/**
	 * 拼装其他演员的信息
	 *
	 * @return 信息
	 */
	protected abstract String getOtherInfo();
}

/**
 * 地牢统治者
 */
public class DungeonMaster extends Actors {
	/**
	 * 职责
	 */
	private String performance;

	public String getPerformance() {
		return performance;
	}

	public void setPerformance(String performance) {
		this.performance = performance;
	}

	@Override
	protected String getOtherInfo() {
		return "职责:" + this.performance + "\t";
	}
}

/**
 * 平家Boy
 */
public class PingjiaBoy extends Actors {
	/**
	 * 工作内容
	 */
	private String job;

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	@Override
	protected String getOtherInfo() {
		return "工作内容:" + this.job + "\t";
	}
}

入口类方法

public static void mockActors() {
	List<Actors> actors = new ArrayList<>();
	// 马凯
	PingjiaBoy makai = new PingjiaBoy();
	makai.setName("马凯");
	makai.setPosition(Actors.SLAVE);
	makai.setPower(0);
	makai.setJob("Show~ Yes Sir");
	// 吾作
	PingjiaBoy wuzuo = new PingjiaBoy();
	wuzuo.setName("吾作");
	wuzuo.setPosition(Actors.SLAVE);
	wuzuo.setPower(0);
	wuzuo.setJob("Show~ Yes Sir");
	// 地牢统治者
	DungeonMaster van = new DungeonMaster();
	van.setName("Van");
	van.setPosition(Actors.MASTER);
	van.setPower(10000);
	van.setPerformance("Take it boy");
	actors.add(van);
	actors.add(makai);
	actors.add(wuzuo);

	for (Actors actor : actors) {
		actor.report();
	}
}

结果

设计模式——访问者模式_第1张图片

访问者模式

小结

  1. 三个变动。删除report()方法,增加accept()方法,删除getOtherInfo()方法
  2. 即Actors都可以被访问者访问

UML图

设计模式——访问者模式_第2张图片

演员的抽象和实现

/**
 * 我们都是演员 抽象类
 */
public abstract class Actors {
	public final static int SLAVE = 0;
	public final static int MASTER = 1;

	private String name;
	private int power;
	private int position;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPower() {
		return power;
	}

	public void setPower(int power) {
		this.power = power;
	}

	public int getPosition() {
		return position;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	/**
	 * 拼装其他演员的信息
	 */
	public abstract void accept(IVisitor visitor);
}

/**
 * 地牢统治者
 */
public class DungeonMaster extends Actors {
	/**
	 * 职责
	 */
	private String performance;

	public String getPerformance() {
		return performance;
	}

	public void setPerformance(String performance) {
		this.performance = performance;
	}

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}

/**
 * 平家Boy
 */
public class PingjiaBoy extends Actors {
	/**
	 * 工作内容
	 */
	private String job;

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}

访问者抽象和实现

/**
 * 观众老爷 访问者接口
 */
public interface IVisitor {
	/**
	 * 定义可以访问的平家boy
	 */
	void visit(PingjiaBoy pingjiaBoy);

	/**
	 * 定义可以访问的master
	 */
	void visit(DungeonMaster master);
}

/**
 * 访问者实现
 */
public class Visitor implements IVisitor {
	@Override
	public void visit(PingjiaBoy pingjiaBoy) {
		System.out.println(getPingjiaBoyInfo(pingjiaBoy));
	}

	@Override
	public void visit(DungeonMaster master) {
		System.out.println(getDungeonMasterInfo(master));
	}

	/**
	 * 组装演员的基本信息
	 *
	 * @param actor 演员对象
	 * @return 演员对象的基本信息
	 */
	private String getBaseInfo(Actors actor) {
		String info = "姓名:" + actor.getName() + "\t";
		info += "身份:" + (actor.getPosition() == Actors.SLAVE ? "平家boy" : "Dungeon Master") + "\t";
		info += "权力:" + actor.getPower() + "\t";
		return info;
	}

	/**
	 * 组装master的信息
	 *
	 * @param master master对象
	 * @return master的信息
	 */
	private String getDungeonMasterInfo(DungeonMaster master) {
		String info = this.getBaseInfo(master);
		String masterInfo = "职责:" + master.getPerformance() + "\t";
		return info + masterInfo;
	}

	/**
	 * 组装平家boy的信息
	 *
	 * @param pingjiaBoy 平家boy对象
	 * @return 平家boy的信息
	 */
	private String getPingjiaBoyInfo(PingjiaBoy pingjiaBoy) {
		String info = this.getBaseInfo(pingjiaBoy);
		String pingjiaBoyInfo = "工作内容:" + pingjiaBoy.getJob() + "\t";
		return info + pingjiaBoyInfo;
	}
}

入口类方法

public static void visitor() {
	List<Actors> actors = new ArrayList<>();
	// 马凯
	PingjiaBoy makai = new PingjiaBoy();
	makai.setName("马凯");
	makai.setPosition(Actors.SLAVE);
	makai.setPower(0);
	makai.setJob("Show~ Yes Sir");
	// 吾作
	PingjiaBoy wuzuo = new PingjiaBoy();
	wuzuo.setName("吾作");
	wuzuo.setPosition(Actors.SLAVE);
	wuzuo.setPower(0);
	wuzuo.setJob("Show~ Yes Sir");
	// 地牢统治者
	DungeonMaster van = new DungeonMaster();
	van.setName("Van");
	van.setPosition(Actors.MASTER);
	van.setPower(10000);
	van.setPerformance("Take it boy");
	actors.add(van);
	actors.add(makai);
	actors.add(wuzuo);

	IVisitor visitor = new Visitor();
	for (Actors actor : actors) {
		actor.accept(visitor);
	}
}

结果

设计模式——访问者模式_第3张图片

参考书籍

秦小波《设计模式之禅》

你可能感兴趣的:(设计模式,设计模式,访问者模式,java)