访问者模式实现在源代码不可用的情况下 [英] Visitor pattern implementation in case of source code un-availability

查看:175
本文介绍了访问者模式实现在源代码不可用的情况下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑



在这种情况下,双重发送不是



所以通常首选哪个选项?



选项1 : 在第三方类之上再扩展一个继承层次结构,并实现模式,如图所示,双重发送?



B类的一个等级体系扩展了A类,我将添加

  ElementA extends A 
ElementB extends B

现在ConcreteElements派生自ElementA而不是A类。



缺点:课程数量会增加。



选项2: 使用Visitor类为中心助手类,并完成工作单发。



缺点:我们并不真的按照UML图来跟随Visitor图案。



如果我错了,请更正。

解决方案

您可以结合 Wrapper 访问者来解决您的问题。
使用包装器添加 访问方法可以增加这些对象的可用性。当然,您可以获得包装器的全部优势(较少依赖于旧版类别)和缺点(附加对象)。






这是JAVA中的一个处理例子(因为它是非常严格的,不会自己做双重调度,我很熟悉它):



1)您的旧对象



假设您拥有旧对象 Legacy1 Legacy2 您不能更改,具有特定的业务方法:

  public final class Legacy1 {
public void someBusinessMethod1(){
...
}
}

  public final class Legacy2 {
public void anotherBusinessMethod(){
...
}
}



2)准备Wrapper



您只需将它们包装在 VisitableWrapper 中,该 访问访问者的方法,如:

  public interface VisitableWrapper {
public void accept (访客访客);
}

通过以下实现:

  public class Legacy1Wrapper {

private final Legacy1 legacyObj;

public Legacy2Wrapper(Legacy1 original){
this.legacyObj = original;
}

public void accept(访客访问者){
visitor.visit(legacyObj);
}
}

  public class Legacy2Wrapper {

private final Legacy2 legacyObj;

public Legacy2Wrapper(Legacy2 original){
this.legacyObj = original;
}

public void accept(访客访问者){
visitor.visit(legacyObj);
}
}



3)访客,准备好了!



然后,您自己的访问者可以设置为访问包装器:

  public interface Visitor {
public void visit(Legacy1 leg);
public void visit(Legacy2 leg);
}

执行如下:

  public class SomeLegacyVisitor {

public void visit(Legacy1 leg){
System.out.println(This is a Legacy1!让我们做一些事情!);
leg.someBusinessMethod1();
}

public void visit(Legacy2 leg){
System.out.println(哼,这是一个旧的2对象,嗯,让我们做别的事情。 ;
leg.anotherBusinessMethod();
}
}



4)释放电源



最后在你的代码中,这个框架可以这样工作:

  public class TestClass {
//从一些传统对象开始
Legacy1 leg1 = ...
Legacy2 leg2 = ...

//将所有遗留对象包装到列表中:
列表< VisitableWrapper> visitableLegacys = new ArrayList<>();
visitableLegacys.add(new Legacy1Wrapper(legacy1));
visitableLegacys.add(new Legacy2Wrapper(legacy2));


访客访问者= new SomeLegacyVisitor(); //使用您的任何访问者实现! (VisitableWrapper wrappedLegacy:visitableLegacys)
{
wrappedLegacy.accept(visitor);
}
}

预期输出:

 这是一个Legacy1!让我们一起做吧! 
哼,这是一个Legacy 2对象。嗯,让我们做别的事情

缺点:


  1. 很多样板。如果您使用Java开发,请使用 Lombok

  2. 很多包装对象实例。可能或不是您的问题。

  3. 您需要事先知道对象的具体类型。这意味着你知道他们的子类型,它们不是List中的bundle。如果是这样的话,你别无选择,只能使用反射。


One of the reasons to consider the Visitor_pattern:

A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures.

Assume that you don't have the source code of third party libraries and you have added one operation on related objects.

Since you don't have object, your elements (Third party classes) can't be modified to add Visitor.

In this case, double dispatch is not possible.

So which option is generally preferred?

Option 1: Extend one more inheritance hierarchy on top of third party class and implement pattern as show in picture with double dispatch?

For a given hierarchy of Class B which extends Class A, I will add

ElementA extends A
ElementB extends B

Now ConcreteElements are derived from ElementA instead of class A.

Cons: The number of classes will grow.

Option 2: Use Visitor class a central helper class and get the work done with single dispatch.

Cons: We are not really following Visitor patter as per UML diagram.

Correct if I am wrong.

解决方案

You could combine a Wrapper and Visitor to solve your problems. Using the wrapper to add a visit method allows you to increase the usability of these objects. Of course you get the full advantages (less dependency on the legacy classes) and disadvantages (additional objects) of a wrapper.


Here's a worked-up example in JAVA (because it is pretty strict, does not do double-dispatch by itself, and I'm quite familiar with it):

1) Your legacy Objects

Assuming you have your legacy objects Legacy1 and Legacy2which you cannot change, which have specific business methods:

public final class Legacy1 {
    public void someBusinessMethod1(){
        ...
    }
}

and

public final class Legacy2 {
    public void anotherBusinessMethod(){
        ...
    }
}

2) Prepare the Wrapper

You just wrap them in a VisitableWrapper which has a visit method that takes your visitor, like:

public interface VisitableWrapper {
    public void accept(Visitor visitor);
}

With the following implementations:

public class Legacy1Wrapper {

    private final Legacy1 legacyObj;

    public Legacy2Wrapper(Legacy1 original){
        this.legacyObj = original;
    }

    public void accept(Visitor visitor){
         visitor.visit(legacyObj);
    }
}

and

public class Legacy2Wrapper {

    private final Legacy2 legacyObj;

    public Legacy2Wrapper(Legacy2 original){
        this.legacyObj = original;
    }

    public void accept(Visitor visitor){
         visitor.visit(legacyObj);
    }
}

3) Visitor, at the ready!

Then your own Visitors can be set to visit the wrapper like so:

public interface Visitor {
     public void visit(Legacy1 leg);
     public void visit(Legacy2 leg);
}

With an implementation like so:

public class SomeLegacyVisitor{

    public void visit(Legacy1 leg){
        System.out.println("This is a Legacy1! let's do something with it!");
        leg.someBusinessMethod1();
    }

    public void visit(Legacy2 leg){
        System.out.println("Hum, this is a Legacy 2 object. Well, let's do something else.");
        leg.anotherBusinessMethod();
    }
}

4) Unleash the power

Finally in your code, this framework would work like this:

public class TestClass{
    // Start off with some legacy objects
    Legacy1 leg1 = ...
    Legacy2 leg2 = ...

    // Wrap all your legacy objects into a List:
    List<VisitableWrapper> visitableLegacys = new ArrayList<>();
    visitableLegacys.add(new Legacy1Wrapper(legacy1));
    visitableLegacys.add(new Legacy2Wrapper(legacy2));


    Visitor visitor = new SomeLegacyVisitor(); // Use any of your visitor implementation !
    for(VisitableWrapper wrappedLegacy: visitableLegacys){
        wrappedLegacy.accept(visitor);
    }
}

The expected output:

This is a Legacy1! let's do something with it!
Hum, this is a Legacy 2 object. Well, let's do something else.

Drawbacks:

  1. Quite a lot of boilerplate. Use Lombok if you develop in Java.
  2. Quite a lot of wrapper objects instances. May or may not be a problem for you.
  3. You need to know the specific type of the objects beforehand. This implies you know their subtype, they aren't bundles in a List. If that's the case, you have no other option but to use reflection.

这篇关于访问者模式实现在源代码不可用的情况下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆