访问者模式做了什么?
访问者模式做的事:由访问者本身提供访问方法,而不是由被访问者提供。该模式适合于被访问者相对固定,而访问者时长变化的情况。
Visitor 实际应用
通常在业务开发中访问者模式的应用场景并不多,在《设计模式可复用面向对象软件的基础》一书中举的场景是 单词的拼写检测和断字处理 。那么在实际的应用中,不知道大家有没有了解过 ASM (一个可以动态生成编辑 Java 字节码的框架)感兴趣的同学可以到它的官网看看 https://asm.ow2.io/ , 在 ASM 框架中就广泛应用了 Visitor 的设计模式。
那么上述的例子可能都不是那么简单容易理解,我这里带入一个简单的场景来带大家理解这个模式
消息场景需求:我在一个群组中发送了一条消息,而这条消息需要根据不同的访问者进行差异化的展示,我该怎么做程序代码的设计呢?
首先给出消息类:
public class Message { protected String context; protected Long fromId; protected Long toId; }
public class ImgMessage extends Message{ private String url; }
同时我们会有很多不同的访问者比如:
public interface MessageVisitor { }
public class ManagerVisitor implements MessageVisitor{ }
public class SenderVisitor implements MessageVisitor{ }
public class RecipientVisitor implements MessageVisitor{ }
如何对不同的访问者做消息展示的差异化呢?可能我们会倾向于在 Message 类中写逻辑 (首先声明这种设计并无问题,只是需要根据场景进行分析那种设计更为合适)去做分支逻辑判断
于是 Message 类变成了下面这样:
public class Message { protected String context; protected Long fromId; protected Long toId; public String getContext() { return context; } public void setContext(String context) { this.context = context; } public Long getFromId() { return fromId; } public void setFromId(Long fromId) { this.fromId = fromId; } public Long getToId() { return toId; } public void setToId(Long toId) { this.toId = toId; } public void visit(MessageVisitor messageVisitor){ if (messageVisitor==null){ return; } if (messageVisitor instanceof ManagerVisitor){ System.out.println("管理员看到的文字"+context); }else if (messageVisitor instanceof RecipientVisitor){ System.out.println("接收者看到的文字"+context); }else if (messageVisitor instanceof SenderVisitor){ System.out.println("发送者看到的文字"+context); } } }
public class ImgMessage extends Message{ private String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } @Override public void visit(MessageVisitor messageVisitor){ if (messageVisitor==null){ return; } if (messageVisitor instanceof ManagerVisitor){ System.out.println("管理员看到的图片"+context+" "+url); }else if (messageVisitor instanceof RecipientVisitor){ System.out.println("接收者看到的图片"+context+" "+url); }else if (messageVisitor instanceof SenderVisitor){ System.out.println("发送者看到的图片"+context+" "+url); } } }
主函数
public class Main { public static void main(String[] args) { Message message=new Message(); message.setContext("大家好呀"); ManagerVisitor managerVisitor=new ManagerVisitor(); SenderVisitor senderVisitor=new SenderVisitor(); RecipientVisitor recipientVisitor=new RecipientVisitor(); message.visit(managerVisitor); message.visit(senderVisitor); message.visit(recipientVisitor); ImgMessage imgMessage=new ImgMessage(); imgMessage.setContext("好看的图片"); imgMessage.setUrl("http://img.url.nice.png"); imgMessage.visit(managerVisitor); imgMessage.visit(senderVisitor); imgMessage.visit(recipientVisitor); } }
结果:
管理员看到的文字大家好呀 发送者看到的文字大家好呀 接收者看到的文字大家好呀 管理员看到的图片好看的图片 http://img.url.nice.png 发送者看到的图片好看的图片 http://img.url.nice.png 接收者看到的图片好看的图片 http://img.url.nice.png
这种设计在消息访问角色不常变化的时候是没有任何问题的,然而如果我们的角色会频繁的增加,这种设计的问题就会显露出来,我们每加一个角色就需要在所有的消息类中增加代码判断逻辑,这不符合开闭原则。
这个时候就可以考虑使用访问者模式,将访问的逻辑交由访问者本身来实现,这就需要每个访问者实现所有消息的访问方法
实现统一的访问者接口
public interface MessageVisitor { void visitMessage(Message message); void visitImgMessage(ImgMessage imgMessage); }
public class ManagerVisitor implements MessageVisitor { @Override public void visitMessage(Message message) { System.out.println("管理员访问消息" + message.getContext()); } @Override public void visitImgMessage(ImgMessage imgMessage) { System.out.println("管理员访问图片" + imgMessage.getContext() + " " + imgMessage.getUrl()); } }
public class RecipientVisitor implements MessageVisitor{ @Override public void visitMessage(Message message) { System.out.println("接收方访问消息" + message.getContext()); } @Override public void visitImgMessage(ImgMessage imgMessage) { System.out.println("接收方访问图片" + imgMessage.getContext() + " " + imgMessage.getUrl()); } }
public class SenderVisitor implements MessageVisitor{ @Override public void visitMessage(Message message) { System.out.println("发送方访问消息" + message.getContext()); } @Override public void visitImgMessage(ImgMessage imgMessage) { System.out.println("发送方访问图片" + imgMessage.getContext() + " " + imgMessage.getUrl()); } }
消息接口实现统一的接受访问者接口,这里如果消息是相对固定的,那么访问者模式会更具备优势
public class Message { protected String context; protected Long fromId; protected Long toId; public String getContext() { return context; } public void setContext(String context) { this.context = context; } public Long getFromId() { return fromId; } public void setFromId(Long fromId) { this.fromId = fromId; } public Long getToId() { return toId; } public void setToId(Long toId) { this.toId = toId; } public void accept(MessageVisitor messageVisitor){ messageVisitor.visitMessage(this); } }
public class ImgMessage extends Message{ private String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } @Override public void accept(MessageVisitor messageVisitor) { messageVisitor.visitImgMessage(this); } }
通过使用访问者模式,如果我新增一个角色,则无需改写任何关于 message 类的代码,只需要新增一个 Visitor 并实现相关方法即可,如增加一个子管理员角色
public class SubManagerVisitor implements MessageVisitor{ @Override public void visitMessage(Message message) { System.out.println("子管理员访问消息" + message.getContext()); } @Override public void visitImgMessage(ImgMessage imgMessage) { System.out.println("子管理员访问图片" + imgMessage.getContext() + " " + imgMessage.getUrl()); } }
主方法:
public class Main { public static void main(String[] args) { Message message=new Message(); message.setContext("大家好呀"); ManagerVisitor managerVisitor=new ManagerVisitor(); SenderVisitor senderVisitor=new SenderVisitor(); RecipientVisitor recipientVisitor=new RecipientVisitor(); SubManagerVisitor subManagerVisitor=new SubManagerVisitor(); message.accept(managerVisitor); message.accept(senderVisitor); message.accept(recipientVisitor); message.accept(subManagerVisitor); ImgMessage imgMessage=new ImgMessage(); imgMessage.setContext("好看的图片"); imgMessage.setUrl("http://img.url.nice.png"); imgMessage.accept(managerVisitor); imgMessage.accept(senderVisitor); imgMessage.accept(recipientVisitor); imgMessage.accept(subManagerVisitor); } }
执行结果:
管理员访问消息大家好呀 发送方访问消息大家好呀 接收方访问消息大家好呀 子管理员访问消息大家好呀 管理员访问图片好看的图片 http://img.url.nice.png 发送方访问图片好看的图片 http://img.url.nice.png 接收方访问图片好看的图片 http://img.url.nice.png 子管理员访问图片好看的图片 http://img.url.nice.png
所以访问者模式适用的场景:被访问者结构相对稳定时适合使用 Visitor 访问者模式
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)