Review the following model:
interface Context {
BeanFactory getBeanFactory(); // public method
void refresh(); // public method
void destroy(); // public method
}
interface BeanFactory {
<T> T getBean(String id); // public method
void destroyBeans(); // should be private method for user, but visible for Context
}
class ContextImpl implements Context {
private BeanFactory beanFactory;
@Override
public void destroy() {
beanFactory.destroyBeans();
}
}
ContextImpl
uses BeanFactory
interface, that's why method destroyBeans()
is placed there. But I don't want it to be there, because it is internal API and should be hidden from user.
I thought of using AbstractBeanFactory
reference with protected destroyBeans()
method inside Context
. That will solve the problem of exposing method to end user, but will replace the interface with abstract class.
Another variant is to make another interface, that will extend end-user interface, and use it inside Context. This will break the ability for user to create his own BeanFactory implentations.
I wanted to know if there is a well-known solution for the problem or just see another alternatives.
You can separate your user-facing methods into a user-facing interface, the rest in another one.
interface Context {
BeanFactory getBeanFactory(); // public method
void refresh(); // public method
void destroy(); // public method
}
interface BeanFactory {
<T> T getBean(String id); // public method
}
interface DestroyableBeanFactory extends BeanFactory {
void destroyBeans(); // should be private method for user, but visible for Context
}
class ContextImpl implements Context {
private DestroyableBeanFactory beanFactory;
// internally we demand a DestroyableBeanFactory but we only
// expose it as BeanFactory
public BeanFactory getBeanFactory() {
return beanFactory;
}
@Override
public void destroy() {
beanFactory.destroyBeans();
}
}
Update: If you're worried about a caller casting your BeanFactory
to DestroyableBeanFactory
and calling destroyBeans()
on it, you can return a read-only view instead:
class ContextImpl implements Context {
private DestroyableBeanFactory beanFactory;
// to be extra safe, we create a read-only wrapper
// for our bean factory
public BeanFactory getBeanFactory() {
return new BeanFactory() { //written as an anon inner class for brevity, ideally you should cache this read-only wrapper instance
public <T> T getBean(String id) {
return beanFactory.getBean(id);
}
};
}
...
}
With this the only way to access the value of the beanFactory
field is through reflection (or, optionally, serialization). But if you only want to defend against naughty developers cutting corners and not a malicious attacker, you should be fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With