专业企业网站设计服务公司,网站群集约化建设通知,西安营销网站建设公司,wordpress+php调优访客模式 无痕模式 区别介绍 访客 [1、2]是众所周知的经典设计模式。 有很多资源对其进行了详细说明。 在不深入研究实现的情况下#xff0c;我将简要提醒一下该模式的概念#xff0c;解释其优点和缺点#xff0c;并提出一些可以使用Java编程语言轻松应用于其的改进。 古典… 访客模式 无痕模式 区别 介绍 访客 [1、2]是众所周知的经典设计模式。 有很多资源对其进行了详细说明。 在不深入研究实现的情况下我将简要提醒一下该模式的概念解释其优点和缺点并提出一些可以使用Java编程语言轻松应用于其的改进。 古典访客 [Visitor] 允许在运行时将一个或多个操作应用于一组对象从而将操作与对象结构分离。 四人帮 该模式基于通常称为的接口。 Visitable具有由模型类和一组来实现Visitors实现为每个相关的模型类方法算法。 public interface Visitable { public void accept(Visitor visitor); } public class Book implements Visitable { ....... Override public void accept(Visitor visitor) {visitor.visit( this )}; ....... } public class Cd implements Visitable { ....... Override public void accept(Visitor visitor) {visitor.visit( this )}; ....... } Visitor { interface Visitor { public void visit(Book book); public void visit(Magazine magazine); public void visit(Cd cd); } 现在我们可以实现各种visitors 例如 PrintVisitor是提供打印Visitable DbVisitor其存储在数据库中的DbVisitor 将其添加到购物车的ShoppingCart 等等 访客模式的缺点 visit()方法的返回类型必须在设计时定义。 实际上在大多数情况下这些方法都是void 。 accept()方法的实现在所有类中都是相同的。 显然我们更喜欢避免代码重复。 每次添加新的模型类时每个visitor必须更新因此维护变得很困难。 对于某些visitor 某些模型类不可能有可选的实现。 例如可以通过电子邮件将软件发送给买方而不能发送牛奶。 但是两者都可以使用传统的邮寄方式递送。 因此 EmailSendingVisitor不能实现方法visit(Milk)但可以实现visit(Software) 。 可能的解决方案是引发UnsupportedOperationException但调用者无法提前知道在调用该方法之前将引发此异常。 改进经典访客模式 返回值 首先让我们将返回值添加到Visitor接口。 通用定义可以使用泛型来完成。 public interface Visitable { public R R accept(VisitorR visitor); } interface VisitorR { public R visit(Book book); public R visit(Magazine magazine); public R visit(Cd cd); } 好吧这很容易。 现在我们可以将任何能带来价值的Visitor应用于我们的图书。 例如 DbVisitor可能返回DB整数中已更改记录的数量而ToJson访问者可能会将我们对象的JSON表示形式返回为String。 该示例可能不太有机在现实生活中我们通常使用其他技术将对象序列化为JSON但就其在理论上可以使用Visitor模式而言已经足够了。 默认实现 接下来让我们感谢Java 8在接口内保留默认实现的能力 public interface VisitableR { default R accept(VisitorR visitor) { return visitor.visit( this ); } } 现在实现Visitable类本身不必实现visit() 在大多数情况下默认实现就足够了。 上面建议的改进解决了缺点1和2。 单访客 让我们尝试应用进一步的改进。 首先让我们定义接口MonoVisitor如下 public interface MonoVisitorT, R { R visit(T t); } 名称Visitor被更改为MonoVisitor以避免名称冲突和可能的混淆。 通过这本书 visitor定义了许多重载方法visit() 。 他们每个人都为每个Visitable接受不同类型的参数。 因此根据定义 Visitor不能是通用的。 必须在项目级别上定义和维护它。 MonoVisitor仅定义一种方法。 泛型保证了类型安全。 即使使用不同的通用参数单个类也无法多次实现相同的接口。 这意味着即使将MonoVisitor多个实现分组为一个类我们也必须保留它们。 功能参考而不是访客 由于MonoVisitor只有一种业务方法因此我们必须为每个模型类创建实现。 但是我们不想创建单独的顶级类而是希望将它们分组为一个类。 这个新的visitor在各种Visitable类与java.util.Function实现之间持有Map并将visit()方法的调用分派给特定的实现。 因此让我们看一下MapVisitor。 public class MapVisitorR implements FunctionClass? extends Visitable, MonoVisitor? extends Visitable, R { private final MapClass? extends Visitable, MonoVisitor? extends Visitable, R visitors; MapVisitor(MapClass? extends Visitable, MonoVisitor? extends Visitable, R visitors) { this .visitors visitors; } Override public MonoVisitor apply(Class clazz) { return visitors.get(clazz); } } MapVisitor 实现Function 为了检索特定的实现为便于阅读此处省略了完整的泛型有关详细定义请查看代码段 接收映射中类和实现之间的映射 检索适合给定类的特定实现 MapVisitor具有程序包专用的构造函数。 使用特殊构建器完成的MapVisitor初始化非常简单且灵活 MapVisitorVoid printVisitor MapVisitor.builder(Void. class ) .with(Book. class , book - {System.out.println(book.getTitle()); return null ;}) .with(Magazine. class , magazine - {System.out.println(magazine.getName()); return null ;}) .build(); MapVisitor的用法类似于传统的Visitor someBook.accept(printVisitor); someMagazine.accept(printVisitor); 我们的MapVisitor还有一个好处。 必须实现在传统访问者的接口中声明的所有方法。 但是通常无法实现某些方法。 例如我们想要实现演示动物可以执行的各种动作的应用程序。 用户可以选择一种动物然后通过从菜单中选择特定的动作来使它做某事。 这是动物名单 Duck, Penguin, Wale, Ostrich 这是动作列表 Walk, Fly, Swim. 我们决定按操作设置访问者 WalkVisitor, FlyVisitor, SwimVisitor 。 鸭子可以做所有三个动作企鹅不能飞瓦尔只能游泳 鸵鸟只能行走。 因此如果用户试图使Wale走路或Ostrich飞行我们决定抛出异常。 但是这种行为不是用户友好的。 确实用户只有在按下操作按钮时才会收到错误消息。 我们可能更希望禁用不相关的按钮。 MapVisitor允许这样做而无需其他数据结构或代码重复。 我们甚至不必定义new或扩展任何其他接口。 相反我们更喜欢使用标准接口java.util.Predicate public class MapVisitorR implements FunctionClass? extends Visitable, MonoVisitor? extends Visitable, R, PredicateClass? extends Visitable { private final MapClass? extends Visitable, MonoVisitor? extends Visitable, R visitors; ............... Override public boolean test(Class? extends Visitable clazz) { return visitors.containsKey(clazz); } } 现在我们可以调用函数test()来定义是否必须启用或显示选定动物的操作按钮。 github上提供了此处使用的示例的完整源代码。 结论 本文演示了一些改进这些改进使旧的Visitor模式变得更加灵活和强大。 建议的实现方式避免了实现经典的Vistor模式所需的某些样板代码。 以下是上述改进的简要清单。 这里描述的Visitor visit()方法可以返回值因此可以实现为纯函数[3]该函数有助于将Visitor模式与功能编程范例结合起来。 将整体Visitor接口分成单独的块可以使其更加灵活并简化代码维护。 可以在运行时使用构建器来配置MapVisitor 因此它可能会更改其行为具体取决于仅在运行时已知且在开发过程中不可用的信息。 具有不同返回类型的访问者可以应用于相同的Visitable类。 在接口中完成的方法的默认实现将删除通常用于典型的Visitor实现的许多样板代码。 参考资料 维基百科 区域 纯函数的定义 。 翻译自: https://www.javacodegeeks.com/2019/03/new-life-old-visitor-design-pattern.html访客模式 无痕模式 区别