C # 클래스 라이브러리를 디자인 할 때 인터페이스에 대한 상속을 언제 선택해야합니까?
Processor두 가지 매우 다른 작업을 수행하지만 공통 코드 ( "제어 반전"상황)에서 호출 되는 여러 클래스가 있습니다.
에서 상속해야하는지 BaseProcessor아니면 IProcessor인터페이스로 구현 해야하는지 결정할 때 어떤 디자인 고려 사항을인지해야하는지 궁금합니다 .
일반적으로 규칙은 다음과 같습니다.
- 상속은 is-a 관계를 설명합니다 .
- 인터페이스 구현은 할 수있는 관계를 설명합니다 .
좀 더 구체적인 용어로 설명하기 위해 예를 살펴 보겠습니다. System.Drawing.Bitmap클래스 는 이미지 ( 따라서 클래스 에서 상 속됨 Image)이지만 폐기 도 할 수 있으므로 IDisposable인터페이스를 구현합니다 . 또한 직렬화를 수행 할 수 있으므로 ISerializable인터페이스 에서 구현합니다 .
그러나 더 실질적으로 인터페이스는 종종 C #에서 다중 상속을 시뮬레이션하는 데 사용됩니다. Processor클래스가에서 상속해야하는 경우 인터페이스 System.ComponentModel.Component를 구현할 수밖에 없습니다 IProcessor.
사실은 인터페이스와 추상 기본 클래스 모두 특정 클래스가 수행 할 수있는 작업을 지정하는 계약을 제공한다는 것입니다. 이 계약을 선언하는 데 인터페이스가 필요하다는 것은 일반적인 신화이지만 올바르지 않습니다. 내 생각에 가장 큰 장점은 추상 기본 클래스를 사용하여 하위 클래스에 대한 기본 기능을 제공 할 수 있다는 것입니다. 그러나 의미가있는 기본 기능이없는 경우 메서드 자체를으로 표시하는 것을 막을 수있는 방법이 없으므로 abstract파생 클래스가 인터페이스를 구현하는 것처럼 직접 구현해야합니다.
이와 같은 질문에 대한 답을 얻으려면 클래스와 인터페이스 중에서 선택하는 방법에 대해 설명하는 .NET Framework Design Guidelines 를 자주 참조합니다 .
일반적으로 클래스는 추상화를 노출하는 데 선호되는 구성입니다.
인터페이스의 가장 큰 단점은 API 진화를 허용 할 때 클래스보다 훨씬 유연하지 않다는 것입니다. 인터페이스를 제공하면 해당 멤버 세트가 영구적으로 고정됩니다. 인터페이스에 추가하면 인터페이스를 구현하는 기존 유형이 손상됩니다.
클래스는 훨씬 더 많은 유연성을 제공합니다. 이미 제공 한 클래스에 구성원을 추가 할 수 있습니다. 메서드가 추상이 아닌 한 (즉, 메서드의 기본 구현을 제공하는 한) 기존 파생 클래스는 변경되지 않고 계속 작동합니다.
[. . . ]
인터페이스를 선호하는 가장 일반적인 주장 중 하나는 구현에서 계약을 분리 할 수 있다는 것입니다. 그러나 인수는 클래스를 사용하여 구현에서 계약을 분리 할 수 없다고 잘못 가정합니다. 구체적인 구현과 별도의 어셈블리에있는 추상 클래스는 이러한 분리를 달성하는 좋은 방법입니다.
일반적인 권장 사항은 다음과 같습니다.
- 마 인터페이스를 통해 클래스를 정의 선호.
- 마 구현에서 계약을 분리하는 대신 인터페이스의 추상 클래스를 사용합니다. 추상 클래스는 올바르게 정의 된 경우 계약과 구현간에 동일한 수준의 분리를 허용합니다.
- 마십시오 당신이 치 형의 다형성 계층 구조를 제공해야하는 경우 인터페이스를 정의합니다.
- 다중 상속과 유사한 효과를 얻으려면 인터페이스 정의를 고려하십시오 .
크리스 앤더슨은이 마지막 신조에 특별한 동의를 표하며 다음과 같이 주장합니다.
추상 유형은 버전을 훨씬 더 잘 수행하고 향후 확장 성을 허용하지만 유일하고 유일한 기본 유형도 태 웁니다. 인터페이스는 시간에 따라 변하지 않는 두 개체 간의 계약을 실제로 정의 할 때 적합합니다. 추상 기본 유형은 유형 패밀리에 대한 공통 기본을 정의하는 데 더 좋습니다.
리차드,
왜 그들 사이에서 선택합니까? 게시 된 유형 으로 IProcessor 인터페이스 가 있습니다 (시스템의 다른 곳에서 사용하기 위해). IProcessor의 다양한 CURRENT 구현이 공통 동작을 갖는 경우 추상 BaseProcessor 클래스가 해당 공통 동작을 구현하기에 좋은 장소가 될 것입니다.
이런 식으로 BaseProcessor의 서비스가 아닌 IProcessor가 미래에 필요하다면 그것을 가질 필요가 없습니다 (그리고 숨길 수도 있습니다) ...하지만 그것을 원하는 사람들은 그것을 가질 수 있습니다 ... 중복 된 코드 / 개념에서.
내 겸손한 의견입니다.
건배. 키스.
인터페이스는 "계약"이며, 이는 일부 클래스가 속성, 메서드 및 이벤트와 같은 원하는 멤버 집합을 구현하도록 보장합니다.
기본 클래스 (콘크리트 또는 추상, 중요하지 않음)는 일부 엔티티의 원형입니다. 이것은 실제 물리적 또는 개념적 요소에서 공통적 인 것을 나타내는 엔티티입니다.
인터페이스는 언제 사용합니까?
어떤 유형이 선언해야 할 때마다 적어도 소비자가 관심을 갖고 어떤 작업을 수행하기 위해 사용해야하는 행동과 속성이 있습니다.
기본 클래스 (콘크리트 및 / 또는 추상)를 사용하는 경우
엔티티 그룹이 동일한 아키타 입을 공유 할 때마다 B는 차이가있는 A이므로 B는 A를 상속하지만 B는 A로 식별 될 수 있습니다.
예 :
테이블에 대해 이야기합시다.
우리는 재활용 가능한 테이블을 받아들입니다 => 이것은 "IRecyclableTable"과 같은 인터페이스로 정의되어야합니다. 이것은 모든 재활용 가능한 테이블이 "Recycle"메소드를 가지도록 보장합니다 .
We want desktop tables => This must be defined with inheritance. A "desktop table" is a "table". All tables have common properties and behaviors and desktop ones will have same ones adding such things that make a desktop table work different than other types of tables.
I could talk about associations, meaning of both cases in an object graph, but in my humild opinion, if I need to give arguments in a conceptual point of view, I would exactly answer with this argumentation.
I am not pretty good at design choices, but if asked, I will prefer implementing an iProcessor interface if there are only members to be extended. If there are other functions which need not to be extended, inheriting from baseprocessor is better option.
Design purity aside, you can inherit only once so, if you need to inherit some framework class the question is moot.
If you have a choice, pragmatically you can choose the option that saves the most typing. Its usually the purist choice anyway.
EDIT:
If the base class will have some implementation then this could be useful, if it is purely abstact then it may as well be an interface.
If whatever you choose don't matter, always choose Interface. It allows more flexibility. It might protect you from future changes (if you need to change something in the base class, the inherited classes might be affected). It also allow to encapsulate the details better. If you are using some Inversion of Control of Dependency Injection, they tend to favor interface.
Or if inheritance can't be avoided, probably a good idea to use both of them together. Create a abstract base class that implements an interface. In your case, ProcessorBase implements an IProcessor.
Similar to ControllerBase and IController in ASP.NET Mvc.
Given that the SOLID principles offer more maintainability and extensibility to your project, I'd prefer interfaces over inheritance.
Also, if you need to add "additional functionality" to your interface, best option is to create a new interface altogether, following the I in SOLID, which is Interface Seggregation Principle.
'IT박스' 카테고리의 다른 글
| 두 개 이상의 필드에서 가장 큰 값 (0) | 2020.11.13 |
|---|---|
| android mediaRecorder.setAudioSource 실패 (0) | 2020.11.13 |
| 테이블의 기본 키를 얻는 방법은 무엇입니까? (0) | 2020.11.13 |
| MySQL의 열에있는 일부 값에 선행 0 추가 (0) | 2020.11.13 |
| Java Enum 반환 Int (0) | 2020.11.13 |