2011-10-21 151 views
3

我有一種情況,我需要調用第三方服務來獲取一些信息。對於不同的客戶,這些服務可能會不同。我的界面中有一個驗證功能,如下所示。接口實現(接口分離原理)

interface IServiceProvider { 

bool Authenticate(string username, string password); 
} 

class ABCServiceProvider : IserviceProvider 
{ 
bool Authenticate(string username, string password) { // implementation} 
} 

class EFGServiceProvider : IserviceProvider 
{ 
bool Authenticate(string username, string password) { // implementation} 
} 

等等......現在我已經跨越,需要進行身份驗證一些附加信息(的agentId)服務供應商(比方說XYZServiceProvider)來了。這樣的事情...

class XYZServiceProvider 
{ 
bool Authenticate(string username, string password, int agentid) { // implementation} 
} 

現在,如果我提供了另一種身份驗證功能,在我的接口3個參數,並拋出未實現異常在所有類別中,除了XYZServiceProvider,豈不是違反接口隔離原則?我在代碼的其他部分也有類似的情況。任何人都可以告訴我最新的方法來實現這種類型的scenrio?我會非常感激。

回答

4

解決這個問題的最好方法可能是在界面中需要agentId,並且在ABC和DEF不需要它的情況下簡單地忽略它。這樣,消費階層仍然不知道差異。

實際上,如果ABC,DEF和XYZ提供者可以互換使用,那麼Liskov替換原則是最重要的; 「給定一個依賴於類X的類A,X應該能夠使用從A得到的類B而不知道其差別」。

接口隔離原則基本上說接口不應該包含任何消費者不需要的成員,因爲如果這些成員的定義發生改變,甚至不使用該方法的類將不得不成爲重新編譯,因爲他們依賴的接口已經改變。雖然這是相關的(如果添加過載,您必須重新編譯IServiceProvider的所有消費者),但如果您更改Authenticate()的簽名,則無論如何您都必須這樣做,而從維護角度來看,更迫切的問題是如果您添加了Authenticate()的重載,您的客戶現在必須知道他們需要使用哪個重載。這就要求你的消費類知道一個通​​用接口的實現之間的區別,違反了LSP。提供比特定供應商所需信息更多的信息從來都不是問題,但從僅使用兩種輸入的用法中使用XYZ會出現問題。爲了避免這些問題,你總是會使用三參數重載,那爲什麼要使用雙參數?

現在,如果IServiceProvider的當前用法在沒有和不關心agentId的領域,因此很難開始提供它,那麼我會推薦一個Adapter,即具體的X​​YZ提供者插件成,實現您當前的IServiceProvider,並通過一些其他手段提供的agentId使得新供應商的工作,如舊:

public class XYZAdapter: IServiceProvider 
{ 
    private readonly XYZServiceProvider xyzProvider; 
    public XYZAdapter(XYZServiceProvider provider) 
    { 
     xyzProvider = provider; 
    } 

    public void Authenticate(string username, string password) 
    { 
     xyzProvider.Authenticate(username, password, GetAgentId()); 
    } 

    public int GetAgentId() 
    { 
     //Retrieve the proper agent Id. It can be provided from the class creator, 
     //retrieved from a known constant data source, or pulled from some factory 
     //method provided from this class's creator. Any way you slice it, consumers 
     //of this class cannot know that this information is needed. 
    } 
} 

如果這是可行的,它滿足兩個LSP和ISP;接口不必改變以支持LSP,因此防止了ISP通常試圖避免的場景(重新編譯和重新分配依賴關係)。然而,它增加了類的數量,並且強制適配器中的新功能正確地獲得所需的agentId,而不必通過IServiceProvider接口提供它不知道的任何內容。

+0

一致地定義一個新的接口,如IAgentServiceProvider。使XYZserviceProvider實現IAgentServiceProvider。現在應用Adapter模式,其中XYZServiceProvider類是Adaptee。 Adapter類將實現IServiceProvider幷包含IAgentServiceProvider引用 – aknon