동료와 코딩 스타일 충돌이 발생했습니다. 내 동료가 무엇을 할 것 인인터페이스 구현 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
만을 사용하는 코드는 거의 없습니다. 우리의 추상화는 다른 추상화에 의존합니다.IMessageList
과IMessageListProvider
을 동시에 구현할 수 없습니다. '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);
}
}
이 있지만, 위의 방식으로 인터페이스를 전복하지 않고 그가 SomeClass
및 IMessageList
의 구현 사이에 원하는 캡슐을 달성 : 내 동료에 타협으로
MessageList
을 내부 또는 공개로 만들 수 있습니다. 그러나
MessageList
은 언제나 편리함으로 전달되어야하며 실제로는 단순한 것이 아니라는 사실이 내 생각에 사실상 인터페이스의 구현이되기 때문에 우리의 추상화를 방해합니다.
답장을 보내 주셔서 감사합니다. 심지어 나는 "tl; dr"을 제 질문에 말하고 싶습니다. – user875215