Recommendations for using interfaces in code, but hiding internal methods from the end user

Check out 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();
    }
}

ContextImpluses an interface BeanFactory, so the method is placed here destroyBeans(). But I do not want it to be there, because it is an internal API and should be hidden from the user.

I was thinking of using a link AbstractBeanFactorywith a protected destroyBeans()method inside Context. This solves the problem of exposing the method to the end user, but replaces the interface with an abstract class.

Another option is to create another interface that extends the end user interface and uses it in Context. This impairs the user's ability to create their own BeanFactory implants.

, .

+4
2

, , , , - .

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();
    }
}

: , BeanFactory DestroyableBeanFactory destroyBeans() , :

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);
             }
        };
    }
    ...
  }

BeanFactory - (, , ). , , .

+2

:
, .
:

abstract ABeanFactory {
    abstract <T> T getBean(String id);
    final void destroyBeans(){}
}

:

interface Context {
    BeanFactoryPrivate getBeanFactory();
    void refresh(); // public method
    void destroy();
}

interface BeanFactory {
    <T> T getBean(String id);
}

interface BeanFactoryPrivate extends BeanFactory{
    void destroyBeans();
}

class ContextImpl implements Context {
    private BeanFactoryPrivate beanFactory;

    @Override
    public void destroy() {
        beanFactory.destroyBeans();
    }
}

+1

All Articles