问题
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