인터페이스를 사용하지 않는 것이 나쁜 습관입니까? [닫은]


40

인터페이스를 거의 사용하지 않고 다른 코드에서 공통적으로 사용됩니다.

또한 내 코드에서 드물게 하위 클래스와 슈퍼 클래스를 만듭니다 (내 클래스를 만드는 동안).

  • 나쁜 일입니까?
  • 이 스타일을 바꾸시겠습니까?
  • 이 스타일에 부작용이 있습니까?
  • 큰 프로젝트를 수행하지 않았기 때문입니까?

10
이것은 어떤 언어입니까?

2
어떤 언어 외에 어떤 패러다임이 있습니까?
Armando

1
"인터페이스"의 개념이 언어를 초월하지 않습니까? Java에는 내장 인터페이스 유형이 있지만 C ++ 개발자는 종종 인터페이스 (I로 접두사)를 작성하며 모두 동일한 목적으로 사용됩니다.
Ricket

4
@Ricket : 아뇨. 문제는 C ++이 다중 클래스 상속을 제공한다는 것입니다. C ++에서 "인터페이스"는 훨씬 더 개념적이고 실제로는 추상 기반 클래스로 정의한 것을 사용합니다. #
DeadMG

2
@Ricket 아니오, 특히 절차 적 또는 OOP가 아닌 기능적 언어로 작업하는 경우.
대안

답변:


36

인터페이스를 사용하려는 몇 가지 이유가 있습니다.

  1. 인터페이스는 응용 프로그램이 특정 기능을 제공하기 위해 관련이없는 많은 개체 유형을 요구하는 상황에 적합합니다.
  2. 여러 인터페이스를 구현할 수있는 단일 구현을 정의 할 수 있으므로 인터페이스는 기본 클래스보다 융통성이 있습니다.
  3. 기본 클래스에서 구현을 상속 할 필요가없는 상황에서는 인터페이스가 더 좋습니다.
  4. 인터페이스는 클래스 상속을 사용할 수없는 경우에 유용합니다. 예를 들어 구조체는 클래스에서 상속 할 수 없지만 인터페이스를 구현할 수 있습니다.

http://msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80).aspx

인터페이스는 프로그래밍에서 다른 것과 같습니다. 필요하지 않으면 사용하지 마십시오. 나는 그것들이 스타일의 문제로 광범위하게 사용되는 것을 보았지만, 인터페이스가 제공하는 특별한 속성과 기능이 필요하지 않다면, "그 이유 때문에"그것들을 사용하는 것의 이점을 보지 못한다.


13
그의 언어는 명시되지 않았고, 당신의 언어는 너무 구체적입니다. 예를 들어 C ++에서, 구조는 실제로 클래스에서 상속받을 수 있으며, 비추 상베이스를 곱할 수 있습니다.
DeadMG

2
이 답변은 C # 인 것처럼 보이지만 # 4를 꺼내면 Java와 관련이 있으며 C ++에서는 다중 상속이 가능하기 때문에 C ++에만 적용됩니다.
Ricket

2
또한 나는 마지막 진술에 동의하지 않습니다. 프로그래머가해야 할 좋은 습관이 많이 있지만 필요하지 않다고 느끼기 때문에 그렇게하지는 않는다고 생각합니다. 나는 아 케르가 주변을 둘러 보면서 다른 사람들이이 일을하고있는 것을보고, 아마도 그가 그렇게해야한다고 생각하지만 먼저 "왜"를 물어야한다고 생각한다.
Ricket

3
@Ricket : 내 대답의 네 가지 요점에 있습니다. 이러한 이유 중 어느 것도 해당되지 않으면 인터페이스가 필요하지 않습니다.
Robert Harvey

17

클래스 상속과 인터페이스는 모두 그 자리를 차지합니다. 상속은 "는"을 의미하고 인터페이스는 "동작"을 정의하는 계약을 제공합니다.

인터페이스를 더 자주 사용하는 것은 나쁜 습관이 아닙니다. 현재 Bill Wagner의 "효과적인 C #-C # 개선을위한 50 가지 구체적인 방법"을 읽고 있습니다. 항목 번호 22는 "인터페이스에 인터페이스를 정의하고 구현하는 것이 좋습니다"라고 인용합니다.

일반적으로 개념적으로 관련된 유형 간의 공통 동작의 특정 구현을 정의해야 할 때 기본 클래스를 사용합니다. 더 자주 인터페이스를 사용합니다. 사실, 나는 일반적으로 클래스를 만들 때 클래스에 대한 인터페이스를 정의하여 시작합니다 ... 결국 인터페이스를 컴파일하지 않더라도 공용 API를 정의하여 시작하는 것이 도움이된다는 것을 알았습니다. 시작부터 수업. 인터페이스를 구현하는 여러 클래스가 있고 구현 논리가 동일하다는 것을 알게되면 유형 간 공통 기본 클래스를 구현하는 것이 합리적인지 여부를 스스로에게 묻습니다.

Bill Wagners의 인용문은 다음과 같습니다.

모든 파생 클래스는 즉시 해당 동작을 통합합니다. 인터페이스에 멤버를 추가하면 해당 인터페이스를 구현하는 모든 클래스가 중단됩니다. 새로운 메소드를 포함하지 않으며 더 이상 컴파일되지 않습니다. 각 구현자는 새 멤버를 포함하도록 해당 유형을 업데이트해야합니다. 추상 기본 클래스와 인터페이스 중에서 선택하는 것은 시간이 지남에 따라 추상화를 가장 잘 지원하는 방법에 대한 문제입니다. 인터페이스 수정 : 모든 유형이 구현할 수있는 일련의 기능에 대한 계약으로 인터페이스를 릴리스합니다. 기본 수업은 시간이 지남에 따라 확장 될 수 있습니다. 이러한 확장은 모든 파생 클래스의 일부가됩니다. 두 개의 모델을 혼합하여 여러 인터페이스를 지원하면서 구현 코드를 재사용 할 수 있습니다. " 새로운 메소드를 포함하지 않으며 더 이상 컴파일되지 않습니다. 각 구현자는 새 멤버를 포함하도록 해당 유형을 업데이트해야합니다. 추상 기본 클래스와 인터페이스 중에서 선택하는 것은 시간이 지남에 따라 추상화를 가장 잘 지원하는 방법에 대한 문제입니다. 인터페이스 수정 : 모든 유형이 구현할 수있는 일련의 기능에 대한 계약으로 인터페이스를 릴리스합니다. 기본 수업은 시간이 지남에 따라 확장 될 수 있습니다. 이러한 확장은 모든 파생 클래스의 일부가됩니다. 두 개의 모델을 혼합하여 여러 인터페이스를 지원하면서 구현 코드를 재사용 할 수 있습니다. " 새로운 메소드를 포함하지 않으며 더 이상 컴파일되지 않습니다. 각 구현자는 새 멤버를 포함하도록 해당 유형을 업데이트해야합니다. 추상 기본 클래스와 인터페이스 중에서 선택하는 것은 시간이 지남에 따라 추상화를 가장 잘 지원하는 방법에 대한 문제입니다. 인터페이스 수정 : 모든 유형이 구현할 수있는 일련의 기능에 대한 계약으로 인터페이스를 릴리스합니다. 기본 수업은 시간이 지남에 따라 확장 될 수 있습니다. 이러한 확장은 모든 파생 클래스의 일부가됩니다. 두 개의 모델을 혼합하여 여러 인터페이스를 지원하면서 구현 코드를 재사용 할 수 있습니다. " 모든 유형이 구현할 수있는 일련의 기능에 대한 계약으로 인터페이스를 릴리스합니다. 기본 수업은 시간이 지남에 따라 확장 될 수 있습니다. 이러한 확장은 모든 파생 클래스의 일부가됩니다. 두 개의 모델을 혼합하여 여러 인터페이스를 지원하면서 구현 코드를 재사용 할 수 있습니다. " 모든 유형이 구현할 수있는 일련의 기능에 대한 계약으로 인터페이스를 릴리스합니다. 기본 수업은 시간이 지남에 따라 확장 될 수 있습니다. 이러한 확장은 모든 파생 클래스의 일부가됩니다. 두 개의 모델을 혼합하여 여러 인터페이스를 지원하면서 구현 코드를 재사용 할 수 있습니다. "

"코딩 인터페이스는 기본 클래스 유형으로 코딩하는 것보다 다른 개발자에게 더 큰 유연성을 제공합니다."

"인터페이스를 사용하여 클래스의 API를 정의하면 유연성이 향상됩니다."

"유형이 속성을 클래스 유형으로 노출하면 전체 인터페이스가 해당 클래스에 노출됩니다. 인터페이스를 사용하면 클라이언트가 사용할 메소드 및 속성 만 노출하도록 선택할 수 있습니다."

"기본 클래스는 관련 콘크리트 유형에서 공통적 인 동작을 설명하고 구현합니다. 인터페이스는 관련이없는 콘크리트 유형이 구현할 수있는 원자 적 기능을 설명합니다. 둘 다 그 위치를가집니다. 클래스는 생성 한 유형을 정의합니다. 인터페이스는 이러한 유형의 동작을 기능으로 설명합니다. 차이점을 이해하면 변화에보다 탄력적 인 표현 디자인을 더 많이 만들 수 있습니다. 클래스 계층 구조를 사용하여 관련 유형을 정의하십시오. 이러한 유형에 걸쳐 구현 된 인터페이스를 사용하여 기능을 노출하십시오. "


2
글쎄, 나는 그것을 읽고 좋은 대답이라고 생각했다.
Eric King

1
@ mc10 문제가 무엇인지 잘 모르겠습니다. 그는 책을 참조했으며 그의 답변의 하단부는 그 책의 인용문으로 시간을 낭비하고 싶지 않다면 분명히 알려줍니다.
Pete

@Pete 나는 대답이 나쁘다고 말하지는 않았지만 너무 길었다. 나는 당신이 때때로 전체 견적을 필요로했는지 의심합니다.
kevinji 2016 년

3
하하, 이것이 tl; dr이라면,이 전체 Exchange Exchange 고품질 답변을 좋아할 것입니다.
Nic

하하 고마워 예, 대답이 조금 오래되었다는 생각이 들었지만 인터페이스와 상속의 장단점뿐만 아니라 시나리오의 장점과 단점을 설명하는 Wagner 씨의 관련 인용문을 포함하여 답변을받을 것이라고 생각했습니다. 각각 더 적합합니다. 아마도 책을 직접 인용하면 내 대답에 큰 가치가 없었습니다.
John Connelly

8

언급되지 않은 한 가지 테스트는 테스트입니다. 모든 C # mocking-library 및 Java에 대한 일부 클래스 는 인터페이스를 구현하지 않으면 클래스 조롱 할 수 없습니다 . 이는 애자일 / TDD 관행에 따라 모든 클래스에 고유 한 인터페이스 를 제공하는 많은 프로젝트를 이끌고 있습니다.

어떤 사람들은 이것이 "커플 링을 줄이므로"이 모범 사례를 고려하지만 동의하지 않습니다. 언어의 부족에 대한 해결책 일 뿐이라고 생각합니다.


인터페이스는 "동일한"것을 수행하지만 다른 방식으로 수행하는 두 개 이상의 클래스가있을 때 가장 잘 사용된다고 생각합니다.

예를 들어, 닷넷 프레임 워크의 가게에 나와있는 여러 클래스가 물건을 ,하지만 그들은 모두 저장하는 것이 다른 방식으로 물건. 따라서 추상 IList<T>인터페이스 를 갖는 것이 합리적 이며 다른 인터페이스를 사용하여 구현할 수 있습니다.

또한 2+ 클래스를 상호 교환하거나 나중에 교체 할 수 있도록하려는 경우에도 사용해야합니다. 앞으로 목록을 저장하는 새로운 방법이 나오면 코드 전체에서 AwesomeList<T>사용한다고 가정하면 사용 IList<T>하도록 AwesomeList<T>변경하면 수백 / 수천이 아닌 수십 줄만 변경하는 것을 의미합니다.


5

상속과 인터페이스가 적절할 때 사용하지 않는 주요 결과는 긴밀한 결합 입니다. 이것은 인식하기가 다소 어려울 수 있지만 일반적으로 가장 분명한 증상은 변경을 할 때 파급 효과를 변경하기 위해 다른 파일을 많이 사용해야하는 경우가 많습니다.


4

아니, 전혀 나쁘지 않다. 공통 인터페이스가있는 두 클래스를 런타임시 서로 바꿔야하는 경우에만 명시 적 인터페이스를 사용해야합니다. 상호 교환이 필요하지 않으면 상속받지 않아도됩니다. 그렇게 간단합니다. 상속은 깨지기 쉬우므로 가능하면 피해야합니다. 피하거나 제네릭을 대신 사용할 수 있다면 그렇게하십시오.

문제는 컴파일 타임 제네릭이 약한 C # 및 Java와 같은 언어에서 모든 클래스가 동일한 기반에서 상속되지 않으면 둘 이상의 클래스를 처리 할 수있는 하나의 메서드를 작성할 수 없기 때문에 DRY를 위반할 수 있다는 것입니다. C # 4 는 이것을 처리 dynamic 할 수 있습니다 .

문제는 상속은 전역 변수와 같습니다. 일단 변수를 추가하고 코드에 의존하면 하나님은 그것을 제거하도록 도와줍니다. 그러나 언제든지 추가 할 수 있으며 정렬 래퍼를 사용하여 기본 클래스를 변경하지 않고 추가 할 수도 있습니다.


1
공감 사유?
DeadMG

확실하지 않습니다. 공감하십시오. 좋은 대답이었습니다.
Bryan Boettcher

3

그렇습니다. 인터페이스를 사용하지 않는 (또는 너무 드물게) 아마 나쁜 것입니다. 인터페이스 (추상적 인 의미에서, C # / Java 언어 구성은 그 추상적 인 의미와 매우 유사하다)는 시스템과 하위 시스템 간의 명시적인 상호 작용 지점을 정의합니다. 이는 커플 링을 줄이고 시스템을보다 유지 보수하기 쉽게 만듭니다. 유지 관리 성을 향상시키는 것과 마찬가지로 시스템이 클수록 중요합니다.


3

몇 년 동안 인터페이스를 사용하지 않았습니다. 물론 이것은 몇 년 동안 Erlang에서 거의 독점적으로 프로그래밍 해 왔으며 인터페이스의 전체 개념이 존재하지 않기 때문입니다. (당신이 얻을 가장 가까운는 "행동"이며 정말 열심히 곁눈질하지 않는 한 그건 정말 같은 일이 아니에요 그리고 밖으로 눈의 구석의 그 봐.)

따라서 실제로 귀하의 질문은 패러다임에 의존하고 (이 경우 OOP) 또한 언어에 따라 다릅니다 (인터페이스가없는 OOP 언어가 있습니다).


2

Java 사용에 대해 이야기하는 경우 인터페이스를 사용하는 한 가지 이유는 코드 생성 라이브러리없이 프록시 객체를 사용할 수 있기 때문입니다. 이것은 Spring과 같은 복잡한 프레임 워크로 작업 할 때 실질적인 이점이 될 수 있습니다. 또한, 일부 기능은 필요 인터페이스 : 당신은 당신이 인터페이스의 측면에서 제공하고있는 기능 (으로부터 상속 설명하기 위해 가지고 RMI는, 이것의 전형적인 예입니다 java.rmi.Remote당신이 그들을 구현 가야하지만 참조).


1

상황이 바뀌고 있지만 ( MS Moles ) 인터페이스에 거의 독점적으로 코딩하는 것이 좋을 것이라고 생각하는 주된 이유는 인터페이스를 모의하고 자연스럽게 IoC 아키텍처에 적합시키기 때문입니다.

IMO 인터페이스 만 사용하거나 가능하면 완전히 바보 같은 DAO 만 사용해야합니다. 일단이 사고 방식에 들어 서면 인터페이스를 통해 자신을 노출시키지 않고 내가 정직해야 할 구체적인 객체를 통해 모든 것을 수행하는 라이브러리를 사용하기 시작하면 모든 것이 약간 어색해집니다.


0

구식 프로젝트의 경우 순환 참조는 장기적으로 큰 유지 관리 문제가 될 수 있으므로 순환 참조를 피하기 위해 인터페이스를 사용합니다.

나쁜:

class B; // forward declaration
class A
{
  B* b;
};

class B
{
  A* a;
}

나쁘지 않다:

class PartOfClassB_AccessedByA
{
};

class A
{
  PartOfClassB_AccessedByA* b;
};

class B : public PartOfClassB_AccessedByA
{
  A* a;
}

일반적으로 A, B, PartOfClassB_AccessedByA는 별도의 파일로 구현됩니다.


0

인터페이스 기반 프로그래밍을 통해 코드를보다 유연하고 쉽게 테스트 할 수 있습니다. 클라이언트 클래스를 건드리지 않고 구현 클래스를 변경할 수 있습니다 [유연성]. 코드를 테스트하면 실제 oInterface 기반 프로그래밍을 대체 할 수 있지만 코드를보다 유연하고 쉽게 테스트 할 수 있습니다. 클라이언트 클래스를 건드리지 않고 구현 클래스를 변경할 수 있습니다 [유연성]. 코드를 테스트하는 동안 실제 객체를 모의 객체 [Testability]로 대체 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.