访问者模式
定义
封装一些的对于某种数据结构中的各元素的操作,它可以在不改变数据的前提下定义作用于这些元素的新的操作
访问者模式(Visitor pattern)是相对简单的模式,也可以作为迭代器模式的补充
优缺点、应用场景
优点
- 符合单一职责原则。具体角色负责数据的存储,而访问者对象Visitor负责报表的展示,职责明确区分开来
- 优秀的拓展性。由于单一职责,继续增加visitor对数据操作是容易的。
- 灵活性非常高。可以对不同的角色做定制化处理。
缺点
- 具体角色对访问者公布细节。即visitor关注了具体角色的内部细节,违反了迪米特法则。
- 具体角色变更更困难。具体角色属性的变动会导致visitor中对应角色的逻辑变更。
- 违背了依赖倒置原则。visitor依赖的是具体的角色,而不是抽象,破坏了依赖倒置原则。在面向对象编程中,直接操作具体角色会造成拓展困难。
应用场景
- 一个对象结构包含很多类对象,它们有不同的接口,又需要对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同并且不相关的操作。
模拟场景
打印报表。还原在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;}@Overrideprotected 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;}@Overrideprotected 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();}
}
结果
访问者模式
小结
- 三个变动。删除report()方法,增加accept()方法,删除getOtherInfo()方法
- 即Actors都可以被访问者访问
UML图
演员的抽象和实现
/*** 我们都是演员 抽象类*/
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;}@Overridepublic 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;}@Overridepublic 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 {@Overridepublic void visit(PingjiaBoy pingjiaBoy) {System.out.println(getPingjiaBoyInfo(pingjiaBoy));}@Overridepublic 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);}
}
结果
参考书籍
秦小波《设计模式之禅》