Visitor pattern implementation in case of source code un-availability

前端 未结 6 1532
旧时难觅i
旧时难觅i 2021-01-04 21:48

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 structu

6条回答
  •  鱼传尺愫
    2021-01-04 22:28

    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 implements VisitableWrapper {
    
        private final Legacy1 legacyObj;
    
        public Legacy1Wrapper(Legacy1 original){
            this.legacyObj = original;
        }
    
        public void accept(Visitor visitor){
             visitor.visit(legacyObj);
        }
    }
    

    and

    public class Legacy2Wrapper implements VisitableWrapper {
    
        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 visitableLegacys = new ArrayList<>();
        visitableLegacys.add(new Legacy1Wrapper(legacy1));
        visitableLegacys.add(new Legacy2Wrapper(legacy2));
    
        // Use any of your visitor implementations!
        Visitor visitor = new SomeLegacyVisitor();
        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.

提交回复
热议问题