在代码中使用接口但对最终用户隐藏内部方法的最佳实践

Ada*_*ker 5 java encapsulation interface

查看以下模型:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

ContextImpl使用BeanFactory接口,这就是方法destroyBeans()放置在那里的原因。但我不希望它在那里,因为它是内部 API,应该对用户隐藏。

我想到使用内部AbstractBeanFactory受保护方法的引用。这将解决向最终用户公开方法的问题,但会用抽象类替换接口。destroyBeans()Context

另一种变体是创建另一个接口,该接口将扩展最终用户接口,并在 Context 中使用它。这将破坏用户创建自己的 BeanFactory 实现的能力。

我想知道是否有一个众所周知的解决方案来解决该问题,或者只是看看其他替代方案。

biz*_*lop 4

您可以将面向用户的方法分离到面向用户的界面中,其余的则放在另一个界面中。

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:如果您担心调用者将您的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);
             }
        };
    }
    ...
  }
Run Code Online (Sandbox Code Playgroud)

这样,访问字段值的唯一方法beanFactory是通过反射(或者可选的序列化)。但如果您只想防御顽皮的开发人员偷工减料,而不是恶意攻击者,那么应该没问题。

  • @AdamSkywalker - 别担心。安全问题常常被夸大了。很少有应用程序需要担心恶意代码;此类应用程序包括运行 JavaScript 的浏览器;运行小程序的小程序容器;ETC。 (2认同)