Java: Delegation Pattern and Protected Methods

大兔子大兔子 提交于 2019-12-09 18:21:28

问题


I have been using delegation pattern to wrap an object created by a factory in a 3rd party library. Recently, the library added a protected method in the base class and my wrapper class doesn't work any longer. Does anyone have a good solution without resorting to reflection?

This is in 3rd party library and in their package,

public class Base {
    public void foo();

    protected void bar(); // Newly added
}

This is in my own package,

public class MyWrapper extends Base {
    private Base delegate;

    public MyWrapper(Base delegate) {
        this.delegate = delegate;
    }

    public void foo() {
        delegate.foo()
    }

    protected void bar() {
        // Don't know what to do
    }
}

EDIT: My original post wasn't clear. These 2 classes are in different packages.

To answer the question why I need delegation. This is a typical use-case of Delegation/Wrapper pattern and I can't show it here in a few lines of code. The library exposes Base class but the actual object from their factory is a derived class of Base. The actual class changes depending on configuration. So I don't know what delegate is. Therefore straight inheritance pattern doesn't work here.


回答1:


Access Levels
Modifier    Class   Package Subclass    World
public      Y          Y        Y         Y
protected   Y          Y        Y         N
no modifier Y          Y        N         N
private     Y          N        N         N

protected has package access too, do you see any specific issue with this:

class Base {
        public void foo(){};

        protected void bar(){}; // Newly added
    }

    class MyWrapper  {
        private Base delegate;

        public MyWrapper(Base delegate) {
            this.delegate = delegate;
        }

        public void foo() {
            delegate.foo();
        }

        protected void bar() {
            // Don't know what to do
            delegate.bar(); //since its in same package, it can be referenced, do you expect compile time error?
        }
    }

Further while using delegator pattern why wrapper class extends Base class, I don't see specific need since you already have an instance of Base. To me it seems more of an decorator.




回答2:


You don't need (or shouldn't?) delegate that bar method.

If the library defined a protected method. It doesn't want user (of course in different package) to invoke that method, unless creating subclass of that type. You are trying to break the rule.

If you want to do it, there is way, you create a subtype of Base,say SubBase, you create object of SubBase instead of Base, then pass subBase to your wrapper. then you could in your wrapper bar() method write delegate.bar() In this way, the SubBase is actually the delegate, or to say your wrapper is delegating SubBase not Base

I think you know what I mean, so I just don't type example codes, only this line I guess it is enough:

//Wrapper

 private SubBase delegate;

You see the wrapper is not necessary any longer if you have SubBase. You could even define a public void pubBar() in your SubBase, and there you call this.bar(). in this way all objects of SubBase have access to the protected method (via pubBar()), no matter from which package




回答3:


I get the impression that the Base class is either an interface or an abstract class. If so, you must implement the bar() method, for example by using any of the three methods listed below.

Side note, if Base is a normal class, you do not have do anything (a call to an instance of MyWrapper.bar() will actually result in a call to Base.bar().


Delegate to the parent object

This is usually a good idea if the bar() method is used as a callback in the 3rd party API:

@Override
protected void bar() {
    delegate.bar();
}

Do nothing

Just added an empty method to avoid compile errors:

@Override
protected void bar() {
    // silently ignored
}

Throw an exception

Violently prevent any usage of the new method:

@Override
protected void bar() {
    throw new UnsupportedOperationException("not implemented");
}

As a side note, a more robust construction is to prefer composition over inheritance to decouple your implementation from the 3rd party implementation, e.g.

public class MyWrapper {    // does not extend Base
    private Base delegate;

    public MyWrapper(Base delegate) {
        this.delegate = delegate;
    }

    public void foo() {
        delegate.foo()
    }

    // does not have to implement bar()
}



回答4:


I'm using Spring for injecting in Wrapper the "Base delegate" from another module and for getting the delegate i'm using a pojo factory.

<bean id="interfaceDelegate" factory-bean="DelegatePojoFactory"
    factory-method="getMyDelegateInstance">
    <constructor-arg index="0">
        <value>OnLine</value>
    </constructor-arg>
</bean>

<bean id="wrapper" class="path.Wrapper">
      <property name="delegate" ref="interfaceDelegate"></property>
</bean>



回答5:


If you don't need your delegator to be an actual instance of the base class, you can simply remove that relation:

public class MyWrapper {
    private Base delegate;

    public MyWrapper(Base delegate) {
        this.delegate = delegate;
    }

    public void foo() {
        delegate.foo()
    }

}

Whether that works for you is highly dependent on your other code, and your needs aren't completely clear to me right now.

If the library defines an interface providing the public method which is implemented by the abstract base class, you could sensibly implement that interface without inheriting from the abstract base class, which might also satisfy your needs.



来源:https://stackoverflow.com/questions/16235436/java-delegation-pattern-and-protected-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!