2015-07-03 31 views
4

查看以下模型:最佳做法使用代碼的接口,但隱藏從最終用戶的內部方法

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使用BeanFactory界面,這就是爲什麼方法destroyBeans()是擺在那裏。但我不希望它在那裏,因爲它是內部API,應該隱藏給用戶。

我想到使用AbstractBeanFactory參考與Context內的受保護destroyBeans()方法。這將解決暴露方法給最終用戶的問題,但將用抽象類替換接口。

另一個變體是創建另一個接口,它將擴展最終用戶界面,並在Context中使用它。這將破壞用戶創建自己的BeanFactory實現的能力。

我想知道是否有一個知名解決方案的問題或只是看到另一種選擇。

+1

對我來說,在界面中假設有私有方法是沒有意義的。顧名思義,它是一個「INTERFACE」,內部實現(我的意思是私有方法)不應該成爲恕我直言。 – Alp

+0

你可以有兩個接口,一個包含getBean()方法,另一個接口擴展它並添加'destroyBeans()'。 – biziclop

回答

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

更新:如果你擔心呼叫者您鑄造BeanFactoryDestroyableBeanFactory,並呼籲它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字段的值的唯一方法是通過反射(或者可選地,序列化)。但是,如果你只是想防禦頑皮的開發者偷偷摸摸而不是惡意攻擊者,那麼你應該沒問題。

+0

暴露'BeanFactory'而不是'DestroyableBeanFactory' +1 – maskacovnik

+0

這是迄今爲止最好的,但是用戶可以施放引用並調用方法。如果我們使接口包本地化,用戶將無法創建BeanFactory實現。這就是爲什麼我想看到其他變體,例如使用其他技術,如助手類。 – AdamSkywalker

+0

@AdamSkywalker在一天結束時,用戶可以使用反射來調用任何方法。如果你需要完全隱藏這個,你可以使用組合而不是繼承。我也會掀起一個例子。 – biziclop

1

看看這個問題:Protected in Interfaces
這是關於保護方法,但有很好的解釋了這個問題。
我會用新的抽象類,因爲這:

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

未測試