1

동료와 코딩 스타일 충돌이 발생했습니다. 내 동료가 무엇을 할 것 인인터페이스 구현 vs. 인터페이스 제공

// Method 1 
class SomeClass : IMessageList { 
    private IList<IMessage> messages = new List<IMessage>(); 
    public AddMessage(IMessage message) { 
     messages.Add(message); 
    } 
    public RemoveMessage(IMessage message) { 
     messages.Remove(message); 
    } 
} 

그러나 이것이다 : 나는 인터페이스를 사용합니다

interface IMessageList { 
    void AddMessage(IMessage message); 
    void RemoveMessage(IMessage message); 
} 

방법은 내가 클래스를 구현해야합니다입니다 : 우리 모두는 말한다, 인터페이스로 시작 :

// Mehod 2 
interface IMessageListProvider { 
    IMessageList MessageList { get; } 
} 
class MessageList : IMessageList { 
    // An implementation similar to the above 
} 
class SomeClass : IMessageListProvider { 
    private IMessageList messageList = new MessageList(); 
    public MessageList { get { return messageList; } } 
} 

그는 그가 마이크로 소프트 코드에서이 방법을 프로그램 아이디어를 얻었으나, 내 연구에 나는이 플러그 싱글의 "마이크로 소프트 고유의 형태 인"공급자 "패턴처럼 들리는 것을 발견 말한다, "하지만 제 동료는 실제로 그것을 사용하지 않습니다. 이것은 그가 인터페이스로 일반적으로 일하는 방법 일뿐입니다. 또한 적절한 상황에서도 제공자 패턴을 비판하는 사람들을 발견했습니다 : http://blog.ploeh.dk/2011/04/27/ProviderIsNotAPattern.aspx, http://www.colourcoding.net/blog/archive/2009/07/29/microsofts-provider-pattern-a-bad-idea-carried-out-to-perfection.aspx. 첫 번째 방법에 관해서는

:

장점 :

  • 그래서, 공급자 패턴 자체의보다 구체적인 문제를 따로 설정, 여기에 프로와 나는 위의 코드 만에서 볼 단점은 하나의 계약 (IMessageList) 만 정의하고 사용하며 IMessageList의 사용은 다른 추상화에 종속되지 않습니다.
  • 하나 쉽게 유도 형의 IMessageList 부재를 무시하고 base.AddMessage 통해베이스 구현에 액세스 할 수 있기 때문에이 확장 가능 등

단점 :

  • 인터페이스의 많은 구현 클래스 이 방법은 많은 방법으로 끝날 것이고 이름 충돌은 더 쉽게 발생할 것입니다.
  • 많은 클래스가 인터페이스 메서드를 구현하고 전달하는 경우 인터페이스에 멤버가있는 수의 전달자가있을 것입니다.
  • SomeClass의 기타 구성 요소와 다른 구성 요소 사이에 캡슐화가 없습니다. 두 번째 방법에 관해서

:

장점 : 많은 클래스가 구현 및 IMessageListProvider를 전달하는 경우

  • 는 단 하나의 방법에 필요한 각에서 재정의한다.
  • IMessageList의 구현은 느슨한 결합을 유지하면서 SomeClass을 벗어나지 않습니다.

단점 :이 방법은 단지를 캡슐화하지 복잡성을 숨기고 업체의 많은 구현

  • .
  • IMessageList은 우리가 정의한 실제 계약이지만 항상 IMessageListProvider을 통과해야하기 때문에 IMessageList만을 사용하는 코드는 거의 없습니다. 우리의 추상화는 다른 추상화에 의존합니다.
  • IMessageListIMessageListProvider을 동시에 구현할 수 없습니다. 'IMessageList'메소드를 사용하는 두 가지 방법이있을 수 있으며 하나는 잘못 될 수 있습니다. 이것은 우리가 정의하고있는 타입에 제한을두고 있지만,이 두 인터페이스를 모두 구현해도 컴파일러 오류가 발생하지는 않습니다.
  • base.MessageList을 호출하면 객체를 제공하기 때문에 IMessageList의 동작을 쉽게 무시할 수 없습니다. 대신 기본 클래스가 사용하는 객체의 하위 클래스를 반환하고이를 확장하려면이 클래스를 재정의해야합니다. 우리가 IMessageList 멤버를 오버라이드 (override)하면 내 방법은

는, 우리는 모든 사람이 IMessageList을 사용하기 때문에 무슨 일이 일어날 것을 알고있다. 그의 방법에서는 IMessageListProvider을 사용하는 클래스를위한 추상적 인 팩토리를 넣을 필요가 있기 때문에 우리가 원하는 것을 구현하는 파생 된 타입을 보낼 수 있습니다. 그러나 이것은 간단한 다형성으로 되돌아 갈 수있는 먼 길로 보입니다. 인터페이스가 수반되어야합니다. 또한 무시하기가 어려우므로 IMessageList의 구현을 하나만 사용하는 것이 좋습니다. 그러나, 우리가 오직 하나의 구체적인 구현만을한다면, 왜 인터페이스의 떼일 것인가? 우리는 계약 (IMessageList)으로 시작했지만 이제는 다른 추상화 (IMessageListProvider)에 의존하고 있습니다.이 작업은 너무 어렵 기 때문에 기본적으로 하나의 유형 (MessageList)을 사용하도록 제한합니다. 우리의 독창적 인 추상화로의 concretion. 간단히 말해서, 나는 그의 방법에서 나쁜 냄새가 난다. 그러나 그는 그 둘 사이의 선택은 단지 스타일의 차이 일 뿐이라는 것을 강력히 주장한다. 그래서 나는 뭔가를 놓치고 있는지 궁금하다. 나는 이것에 대해 다른 견해를 찾을 수 있는지 찾기 위해 많은 조사를 했었지만, 제공자에 따라 특정 패턴이있는 것만을 생각해 냈기 때문에 그들이 얼마나 잘 적용되는지 모른다. 그래서 커뮤니티가 실제로 인터페이스를 구현하는 것보다 속성 게터로 인터페이스를 제공하는 일반적인 스타일에 대해 커뮤니티가 생각하는 것에 대해 궁금합니다.

// Compromise 
class SomeClass : IMessageList { 
    private struct MessageList : IMessageList { 
     private IList<IMessage> messages = new List<IMessage>(); 
     public AddMessage(IMessage message) { 
      messages.Add(message); 
     } 
     public RemoveMessage(IMessage message) { 
      messages.Remove(message); 
     } 
    } 
    private readonly messageList = new MessageList(); 
    public AddMessage(IMessage message) { 
     messageList.Add(message); 
    } 
    public RemoveMessage(IMessage message) { 
     messageList.Remove(message); 
    } 
} 

이 있지만, 위의 방식으로 인터페이스를 전복하지 않고 그가 SomeClassIMessageList의 구현 사이에 원하는 캡슐을 달성 : 내 동료에 타협으로

나는 이런 식으로 뭔가를 제안했다. 또는 다른 클래스에서 사용할 수 있도록 MessageList을 내부 또는 공개로 만들 수 있습니다. 그러나 MessageList은 언제나 편리함으로 전달되어야하며 실제로는 단순한 것이 아니라는 사실이 내 생각에 사실상 인터페이스의 구현이되기 때문에 우리의 추상화를 방해합니다.

답변

0

여기서 볼 수 있듯이 IMessageListProvider에 대한 필요성이 보이지 않습니다. 특히 종속성 주입 프레임 워크를 사용하는 경우 특히 그렇습니다. xxxProvider이있는 경우는 "제공된"객체가 공급자 클래스의 논리에 따라 달라지는 경우입니다. 여기 유효IMessageListProvider을 필요로하는 이유입니다 : 건설 또는 취득

  1. IMessageList 런타임 비싼이며, 그 구성이 가능한 늦게 연기해야한다에.
  2. 구현시 IMessageListProvider 구현에 포함 된 로직에 따라 런타임에 선택해야하는 IMessageList의 여러 가지 구현이 있습니다.

귀하의 설명에서이 두 가지는 사실이 아닙니다. 이것은 cargo cult programming의 명확한 예가되며 IMessageListProvider의 소비자는 Law of Demeter을 위반해야합니다.

+0

답장을 보내 주셔서 감사합니다. 심지어 나는 "tl; dr"을 제 질문에 말하고 싶습니다. – user875215