简体   繁体   中英

Refactor object to use decorator pattern

Using a third party API, I've written wrapper classes for their objects. The obvious/standard way would be this:

public class WrapperFoo implements MyWrapper {
    private Foo f;

    public WrapperFoo(Foo f) {
        this.foo = foo;
    }

    public int getMyParam() {
        return f.getParam();
    }

    public void setMyParam(int param) {
        if(param < 0) throw new IllegalArgumentException("Param must not be negative!");
        f.setParam(param);
    }
}

However, Foo 's get methods are expensive. So instead, I do this:

public class WrapperFoo implements MyWrapper {
    private Foo f;
    private int myParam;

    public WrapperFoo(Foo f) {
        this.foo = foo;
    }

    public int getMyParam() {
        return param;
    }

    public void setMyParam(int param) {
        if(param < 0) throw new IllegalArgumentException("Param must not be negative!");
        this.param = param;
        f.setParam(param);
    }
}

However, for testing reasons, I want to be able to have all the functionality without needing an instance of the third party API. So I want to refactor the existing wrapper version where the third party API functionality is just a decorator:

public class WrapperImpl implements MyWrapper {
    private int myParam;

    public int getMyParam() {
        return myParam;
    }

    public void setMyParam(int param) {
        if(param < 0) throw new IllegalArgumentException("Param must not be negative!");
        this.myParam = param;
    }
}

public class WrapperFoo implements MyWrapper {
    private MyWrapper backing;
    private Foo f;

    public WrapperFoo(MyWrapper backing, Foo f) {
        this.backing = backing;
        this.foo = f;
    }

    public int getMyParam() {
        return backing.getMyParam();
    }

    public void setMyParam(int param) {
        backing.setMyParam(int param);
        f.setParam(param);
    }
}

Obviously, my real classes are a lot more complicated; I fear it will be easy to make a mistake. I suppose that's what tests are for, but... the questions:

  • Primary question In Fowler's Refactoring , each refactoring has a step-by-step process to ensure correctness. Is there one for this process?
  • Does this sort of refactoring have a name? "Extract Decorator"?
  • Does it even make sense to do this (vs. just making a test class from scratch)
  • Is there an IDE that can do this? I'm currently using Eclipse 4.3.1

For a true Decorator/Adapter, the Adapter should have the same interface so your wrapper methods get/setMyParam() should be get/setParam() and if possible you should implement the 3rd party interface if it exists.

Code should not be able to tell the difference between your wrapper and the original from an API perspective.

Now onto your questions:

Primary question: In Fowler's Refactoring, each refactoring has a step-by-step process to ensure correctness. Is there one for this process?

Yes, Joshua Kerievsky's Refactoring to Patterns calls this "Extract Adapter" and there is a step by step example. I can't find an exact code example online but the UML before/after is Here

Does this sort of refactoring have a name? "Extract Decorator"?

As stated before it's called Extract Adapter

Does it even make sense to do this (vs. just making a test class from scratch)

Maybe depends on your usecase.

Is there an IDE that can do this? I'm currently using Eclipse 4.3.1

You can use Eclipse's refactoring tools to perform each step but I would hesitate to try to do a complicated refactoring like you are hinting that you have in a single button push, even if a tool existed that would let you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM