2011-10-21 7 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를 사용할 수 있어야합니다."

Interface Segregation Principle은 기본적으로 인터페이스에 사용자가 필요로하지 않는 멤버가 포함되어서는 안된다고 말합니다. 멤버의 정의가 변경되면 해당 메서드를 사용하지 않는 클래스도 변경되어야하기 때문입니다. 그들이 의존 한 인터페이스가 변경 되었기 때문에 다시 컴파일되었습니다. 이것은 관련이 있지만 (오버로드를 추가하는 경우 IServiceProvider의 모든 소비자를 다시 컴파일해야 함) Authenticate()의 서명을 변경하면 유지 관리 관점에서 더 많은 우려가있을 수 있습니다. 당신은 Authenticate()의 오버로드를 추가 했으므로 이제 소비자는 어떤 오버로드를 사용해야하는지 알 필요가있다. 따라서 소비하는 클래스는 LSP를 위반하는 공통 인터페이스 구현 간의 차이점을 알아야합니다. 특정 공급자가 필요로하는 것보다 많은 정보를 제공하는 것은 결코 문제가되지 않지만 두 입력 만 제공하는 사용법에서 XYZ를 사용하는 데 문제가 있습니다. 이러한 문제를 피하기 위해 항상 3- 매개 변수 오버로드를 사용하므로 두 매개 변수를 모두 사용하는 이유는 무엇입니까?

현재 IServiceProvider의 현재 사용법이 agentId가 없거나 상관하지 않는 영역에 있고 따라서 제공하기가 어려울 경우 구체적인 XYZ 공급자가 플러그인하는 어댑터를 권합니다. 현재 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가 일반적으로 피하려고하는 시나리오 (재 컴파일 및 재배포 의존성)를 방지 할 수 있습니다. 그러나 클래스 수를 늘리고 IServiceProvider 인터페이스를 통해 알지 못하는 것을 제공해야하는 종속 요소없이 필요한 에이전트 ID를 올바르게 가져 오도록 Adapter에 새로운 기능을 강제합니다.

+0

IAgentServiceProvider와 같은 새 인터페이스를 새롭게 정의하십시오. XYZserviceProvider가 IAgentServiceProvider를 구현하도록합니다. 이제 XYZServiceProvider 클래스가 Adaptee 인 어댑터 패턴을 적용합니다. 어댑터 클래스는 IServiceProvider를 구현하고 IAgentServiceProvider 참조를 포함합니다. – aknon