인터페이스 생성시기를 어떻게 알 수 있습니까?


196

개발 학습에서 인터페이스에 대해 더 많이 배워야 할 것 같은 시점에 있습니다.

나는 종종 그들에 대해 읽었지만 그것을 이해할 수없는 것처럼 보입니다.

나는 'Walk', 'Run', 'GetLegs'등과 같은 것들을위한 IAnimal 인터페이스를 가진 Animal base class와 같은 예제를 읽었습니다. 여기!"

내가 무엇을 놓치고 있습니까? 내가 이해하기 어려운 개념 인 이유는 무엇입니까? 나는 그것을 이해하는 데 필요한 부분이 없기 때문에 하나의 구체적인 필요성을 깨닫지 못할 수도 있다는 사실에 겁이 난다! 개발자라는 측면에서 뭔가를 놓친 것처럼 느껴집니다! 누구든지 이와 같은 경험이 있고 획기적인 경우이 개념을 이해하는 방법에 대한 몇 가지 팁을 주셔서 감사합니다. 감사합니다.


1
당신은 체크 아웃해야합니다 stackoverflow.com/q/8531292/1055241
gprathour

답변:


151

이 구체적인 문제를 해결합니다.

4 가지 유형의 a, b, c, d가 있습니다. 코드 전체에 다음과 같은 것이 있습니다.

a.Process();
b.Process();
c.Process();
d.Process();

왜 IProcessable을 구현하지 않았습니까?

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

예를 들어, 모두 같은 일을하는 50 가지 유형의 클래스를 추가하면 확장 성이 훨씬 향상됩니다.


또 다른 구체적인 문제 :

System.Linq.Enumerable을 살펴본 적이 있습니까? IEnumerable을 구현하는 모든 유형에서 작동하는 수많은 확장 메소드를 정의합니다. IEnumerable을 구현하는 것은 기본적으로 "정렬되지 않은 foreach-type 패턴에서 반복을 지원합니다"라고 말하므로 열거 가능한 유형에 대해 복잡한 동작 (Count, Max, Where, Select 등)을 정의 할 수 있습니다.


2
도움이됩니다. 모든 유형이 Process () 메소드에 대한 구현을 갖는 것보다 인터페이스가 존재하는 이점은 무엇입니까?
user53885

모두 동일한 기본 유형의 하위 클래스가 아니거나 인터페이스를 구현하지 않으면 동일한 변수 p를 사용할 수 없습니다.
Karl

Process 메소드를 사용하여 50 개의 다른 클래스와 달리 캐스트 할 필요는 없습니다. C #은 "오리 타이핑"을 사용하지 않으므로 A에 Process ()가 있고 B에 Process ()가 있다고해서 일반적인 호출 방법이 없다는 의미는 아닙니다. 이를위한 인터페이스가 필요합니다.
user7116

권리. 예제를 이해하기 위해 "var"을 "IProcessable"로 변경했습니다.
Jimmy

2
@Rogerio : 나는 일반적인하려고했습니다. 요점은 "Process () 함수가있는 것들이있을 때"가 아니라 "공통적 인 메소드 세트를 공유하는 것들이있을 때"입니다. 예를 다음과 같이 쉽게 변경할 수 있습니다.foreach(IMyCompanyWidgetFrobber a in list) a.Frob(widget, context);
Jimmy

133

나는 지미의 대답을 많이 좋아하지만 그것에 무언가를 추가해야한다고 생각합니다. 모든 일의 핵심은 아이 프로세스의 "수"입니다 . 인터페이스를 구현하는 개체의 기능 (또는 속성이지만 "C # 속성이 아니라"내재적 품질 "을 의미)을 나타냅니다. IAnimal은 아마도 인터페이스에 대한 좋은 예는 아니지만, IWalkable은 시스템이 걸을 수있는 많은 것들을 가지고 있다면 좋은 인터페이스가 될 수 있습니다. Dog, Cow, Fish, Snake와 같은 Animal에서 파생 된 클래스가있을 수 있습니다. 처음 두 개는 아마도 IWalkable을 구현하고 후자 두 개는 걷지 않으므로 그렇게하지 않습니다. 이제 "개와 소에서 파생 된 다른 슈퍼 클래스 인 WalkingAnimal을 왜 가지고 있지 않습니까?"라고 묻습니다. 대답은 로봇과 같이 걸을 수있는 상속 트리 외부에 무언가가있을 때입니다. 로봇은 IWalkable을 구현하지만 Animal에서 파생되지는 않았을 것입니다. 걸을 수있는 것들의 목록을 원한다면

이제 IWalkable을 IPersistable과 같은 소프트웨어로 대체하면 실제 프로그램에서 볼 수있는 것과 훨씬 유사 해집니다.


9
나는 당신이 생각 해낸 것을 좋아합니다- "능력을 나타냅니다". 기본은 "기본"클래스를 고수해야하기 때문에 기능을 정의해야 할 때 인터페이스가 실제로 필요합니다.
Ramiz Uddin

71

동일한 기능의 구현이 다를 경우 인터페이스를 사용하십시오.

공통의 구체적인 구현을 공유해야하는 경우 추상 / 기본 클래스를 사용하십시오.


8
첫 번째는 다형성이라고합니다. 두 번째는 뱀 기름 입니다-sublcass가 기본 클래스 아닌 한 (Liskov 대체 원칙을 위반 하지 않는 한 ) 상속보다 구성을 선호해야합니다.
Arnis Lapsa

@ArnisLapsa "sublcass가 baseclass가 아닌 한"이 무슨 뜻인지 잘 모르겠습니다. 서브 클래스는 언제베이스베이스가되지 않습니까? ( is키워드 에서와 같이 )
Marc.2377

32

계약과 같은 인터페이스를 생각하십시오. "이 클래스는 이러한 규칙을 따라야합니다."라고 말하는 방법입니다.

IAnimal 예제에서는 "IAnimal을 구현하는 클래스에서 Run, Walk 등을 호출 할 수 있어야합니다."라고 말하는 방법입니다.

이것이 왜 유용한가요? 예를 들어 객체에서 Run and Walk를 호출 할 수 있어야한다는 사실에 의존하는 함수를 만들 수 있습니다. 다음을 가질 수 있습니다.

public void RunThenWalk(Monkey m) {
    m.Run();
    m.Walk();
}

public void RunThenWalk(Dog d) {
    d.Run();
    d.Walk();
}

... 걸고 걸을 수있는 모든 물체에 대해 반복하십시오. 그러나 IAnimal 인터페이스를 사용하면 다음과 같이 기능을 한 번 정의 할 수 있습니다.

public void RunThenWalk(IAnimal a) {
    a.Run();
    a.Walk();
}

인터페이스에 대해 프로그래밍하면 인터페이스의 의도를 구현하기 위해 클래스를 기본적으로 신뢰하게됩니다. 우리의 예에서 생각은 "나는 그들이 달리고 걷는 한, 달리고 걷는 방법에 신경 쓰지 않는다 . 내 RunThenWalk는 그 동의를 충족하는 한 유효 할 것입니다. 클래스."

이 관련 질문 에 대한 좋은 토론도 있습니다 .


1
구현 독립성을 잊지 마십시오. 인터페이스를 사용하면 기본 기능이 구현되는 방식을 신경 쓰지 않고 인터페이스가 말하는 기능 만 수행 할 수 있습니다.
Matthew Brubaker

18

너무 걱정하지 마십시오. 많은 개발자들이 인터페이스를 작성할 필요가 거의 없습니다. .NET 프레임 워크 내에서 사용 가능한 인터페이스를 자주 사용 하지만, 언제라도 작성할 필요가 없다고 생각하면 놀라운 일이 없습니다.

내가 항상 누군가에게주는 예는 Sailboat 클래스와 Viper 클래스가있는 경우입니다. 그들은 Boat 클래스와 Car 클래스를 각각 상속받습니다. 이제 이러한 모든 객체를 반복하고 해당 Drive()메소드를 호출해야한다고 가정하십시오 . 다음과 같은 코드를 작성할 수는 있지만

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

작성하는 것이 훨씬 간단합니다.

((IDrivable)myObject).Drive()

16

Jimmy는 여러 유형에 단일 변수를 사용할 수 있기를 원하지만 모든 유형은 인터페이스 선언을 통해 동일한 메소드를 구현합니다. 그런 다음 인터페이스 유형 변수에서 기본 메소드를 호출 할 수 있습니다.

그러나 인터페이스를 사용해야하는 두 번째 이유가 있습니다. 프로젝트 아키텍트가 구현 코더와 다른 사람이거나 여러 구현 코더와 하나의 프로젝트 관리자가있는 경우 담당자는 전체 인터페이스를 작성하고 시스템이 상호 운용되는지 확인한 다음 인터페이스를 구현 클래스로 채울 수 있도록 개발자에게 맡깁니다. 이것은 여러 사람이 호환 가능한 클래스를 작성하고 동시에 수행 할 수있는 가장 좋은 방법입니다.


15

나는 군대 비유를 좋아한다.

상사는 귀하가 소프트웨어 개발자 , 음악가 또는 변호사 인지 상관하지 않습니다 .
당신은 군인 으로 취급됩니다 .

Uml

그것은이다 쉽게 그가 함께 일하고있다 사람의 특정 세부 귀찮게하지 않는 상사에 대한
군인의 추상화로 치료 모두 (... 그들은 사람처럼 행동하지 않을 때이를 처벌).

사람들이 군인처럼 행동하는 능력을 다형성이라고합니다.

인터페이스는 다형성을 달성하는 데 도움이되는 소프트웨어 구성입니다.

필요 단순 귀하의 질문에 대한 답변입니다 달성하기 위해 추상적 인 세부 사항.

어원 적으로 "많은 형태"를 의미하는 다형성 은 기본 클래스의 하위 클래스의 개체를 기본 클래스의 개체 인 것처럼 처리하는 기능입니다. 따라서 기본 클래스는 기본 클래스 자체와 하위 클래스의 여러 형식으로 구성됩니다.

(..) 이렇게하면 코드를보다 쉽게 ​​작성하고 다른 사람들이 쉽게 이해할 수 있습니다. 또한 다른 서브 클래스가 나중에 패밀리 유형에 추가 될 수 있고 새 서브 클래스의 오브젝트도 기존 코드와 함께 작동하므로 코드를 확장 할 수 있습니다.


14

경험상 인터페이스를 만드는 원동력은 조롱 프레임 워크로 단위 테스트를 시작할 때까지 발생하지 않았습니다. 인터페이스를 사용하면 조롱이 훨씬 쉬워 질 것입니다 (프레임 워크가 가상의 방법에 의존하기 때문에). 일단 시작하면 구현에서 클래스로 인터페이스를 추상화하는 가치를 보았습니다. 실제 인터페이스를 만들지 않더라도 이제 메서드를 가상으로 만들려고 시도합니다 (재정의 할 수있는 암시 적 인터페이스 제공).

인터페이스에 대한 리팩토링의 모범 사례를 강화해야하는 다른 많은 이유가 있지만, 단위 테스트 / 조롱은 실제 경험의 초기 "아하 순간"을 제공 한 것이 었습니다.

편집 : 명확히하기 위해 단위 테스트와 조롱으로 항상 실제 구현과 테스트에 사용되는 대체 모의 구현이라는 두 가지 구현이 있습니다. 두 가지 구현이 있으면 인터페이스의 가치가 분명해집니다. 인터페이스와 관련하여 처리하면 언제든지 구현을 바꿀 수 있습니다. 이 경우 모의 인터페이스로 교체합니다. 내 클래스가 올바르게 구성되어 있으면 실제 인터페이스 없이이 작업을 수행 할 수 있지만 실제 인터페이스를 사용하면이 기능이 강화되어 더 명확 해집니다 (독자에게 더 명확합니다). 이러한 자극이 없다면 대부분의 클래스 만 단일 한 구체적인 구현으로 인터페이스의 가치를 높이 평가할 수 없다고 생각합니다.


잘못된 이유로 옳은 일. 귀하의 경우-당신은 소위 "헤더 인터페이스"로 끝나고 단순성에 도달 한 중량 초과 복잡성을 추가했습니다.
Arnis Lapsa

@Arnis-단위 테스트는 "잘못된 이유"이며, 테스트에서 종속성을 제거하기 위해 클래스를 쉽게 조롱하는 것은 "잘못된 이유"입니다. 죄송하지만 동의하지 않습니다.
tvanfosson

1
코드가 테스트 가능하거나 테스트 불가능한 경우 피드백을 제공하여 테스트가 설계에 간접적으로 영향을 미쳐야 합니다. 테스트 가능성 자체를 향상시키기 위해 확장 성 포인트를 추가하는 것은 부정 행위와 같습니다. 나는 마크 시먼은 그것을 가장 요약 생각 bit.ly/esi8Wp을
아르 니스 Lapsa

1
@Arnis-단위 테스트에서 모의를 사용합니까? 그렇지 않은 경우 종속성에 대한 의존성을 어떻게 제거합니까? DI를 전혀 사용하고 있습니까? 단위 테스트를 통해 조롱과 DI를 사용하게되었습니다. 조롱과 DI는 어떤 학문적 이해도 할 수없는 방식으로 계약을 정의하기 위해 인터페이스를 사용하는 모범 사례의 가치를 입증했습니다. TDD를 채택했기 때문에 코드가 다른 것보다 훨씬 덜 결합되어 있습니다. 좋은 생각입니다.
tvanfosson

소위 자연 관절을 따르지 않는 분해는 응집력이 낮고 불필요한 복잡성을 초래합니다.
Arnis Lapsa

10

프로그래밍에서 인터페이스의 적절한 사용을 보는 데 도움이되는 비 프로그래밍 예제

전기 장치와 전기 네트워크 사이에는 인터페이스가 있습니다 . 플러그와 소켓의 모양과 전압 및 전류에 관한 규칙 입니다. 새 전기 장치를 구현하려는 경우 플러그가 규칙을 따르는 한 네트워크에서 서비스를받을 수 있습니다. 이렇게하면 확장 성이 매우 쉬워지고 조정 비용을 제거하거나 줄일 수 있습니다. 전기 공급 업체에 새 장치의 작동 방식을 알리지 않고 새 장치를 네트워크에 연결하는 방법에 대한 별도의 계약을 체결 할 필요가 없습니다.

국가에는 표준 레일 게이지가 있습니다. 이로 인해 레일을 내리는 엔지니어링 회사와 해당 레일에서 기차를 타는 엔지니어링 회사 간의 업무 분담이 가능 해져 철도 회사가 전체 시스템을 재구성하지 않고도 열차 를 교체하고 업그레이드 할 수 있습니다.

비즈니스가 고객에게 제공하는 서비스 는 인터페이스로 설명 할 수 있습니다. 잘 정의 된 인터페이스 는 서비스를 강조하고 수단을 숨 깁니다 . 사서함에 편지를 넣어 때, 당신은 주어진 시간 내에 편지를 전달하기 위해 우편 시스템을 기대하지만 당신은 편지가 전달되는 방법에 대한 어떤 기대를하지 : 당신이 알 필요가 없습니다 , 및 우편 서비스는이 유연성을 요구 사항과 현재 상황에 가장 잘 맞는 운송 수단선택하십시오 . 이에 대한 예외는 고객이 항공 우편을 선택할 수있는 능력입니다. 현대 컴퓨터 프로그래머가 구현 한 인터페이스가 너무 많기 때문에 구현이 너무 많기 때문입니다.

자연의 예 : 나는 eats (), makesSound (), moves () 등의 예에 너무 열중하지 않습니다. 그들은 올바른 행동을 묘사하지만, 상호 작용과 그것이 어떻게 활성화되는지는 설명 하지 않습니다 . 자연의 상호 작용을 가능하게하는 인터페이스의 명백한 예는 번식과 관련이 있습니다. 예를 들어 꽃은 꿀벌에 특정 인터페이스를 제공하여 수분이 발생할 수 있습니다.


5

평생 .net 개발자로 생활하고 자신의 인터페이스를 작성하지 마십시오. 결국, 우리는 수십 년 동안 그것들없이 잘 살아 남았고 우리 언어는 여전히 튜링 완료되었습니다.

왜 인터페이스가 필요한지 말할 수는 없지만 현재 프로젝트에서 인터페이스를 사용하는 위치 목록을 제공 할 수 있습니다.

  1. 플러그인 모델에서는 인터페이스별로 플러그인을로드하고 플러그인 작성자에게 해당 인터페이스를 제공합니다.

  2. 시스템 간 메시징 시스템에서 메시지 클래스는 모두 특정 인터페이스를 구현하며 인터페이스를 사용하여 "포장 해제"됩니다.

  3. 구성 관리 시스템은 구성 설정을 설정하고 검색하는 데 사용되는 인터페이스를 정의합니다.

  4. 불쾌한 순환 참조 문제를 피하기 위해 사용하는 하나의 인터페이스가 있습니다. (필요하지 않은 경우이 작업을 수행하지 마십시오.)

규칙이 있다면 is-a 관계 내에서 여러 클래스를 그룹화하려고 할 때 인터페이스를 사용해야하지만 기본 클래스에서 구현을 제공하고 싶지는 않습니다.


5

코드 예제 (앤드류와 인터페이스가 무엇인지에 대한 추가 정보와 함께 )는 다중 상속 (c # 및 자바):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

FileLogger 및 DataBaseLogger에는 인터페이스가 필요하지 않습니다 (Logger 추상 기본 클래스 일 수 있음). 그러나 기본 클래스를 사용해야하는 써드 파티 로거를 사용해야합니다 (사용해야하는 보호 된 메소드를 노출한다고 가정하십시오). 언어가 다중 상속을 지원하지 않기 때문에 추상 기본 클래스 접근 방식을 사용할 수 없습니다.

결론은 코드에서 유연성을 높이기 위해 가능하면 인터페이스를 사용하는 것입니다. 구현이 덜 묶여 있으므로 변경에 더 적합합니다.


4

나는 지금 인터페이스를 사용했고 여기에 내 최신 사용법이 있습니다 (이름이 일반화되었습니다).

비즈니스 개체에 데이터를 저장해야하는 WinForm에 여러 가지 사용자 지정 컨트롤이 있습니다. 한 가지 방법은 각 컨트롤을 개별적으로 호출하는 것입니다.

myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);

이 구현의 문제점은 컨트롤을 추가 할 때마다 "데이터 저장"방법으로 가서 새 컨트롤을 추가해야한다는 것입니다.

SaveToBusinessObject (...) 메서드가있는 ISaveable 인터페이스를 구현하도록 컨트롤을 변경 했으므로 이제 "데이터 저장"메서드는 컨트롤을 반복하고 ISaveable 인 컨트롤을 찾으면 SaveToBusinessObject를 호출합니다. 이제 새로운 컨트롤이 필요할 때 누군가가해야 할 일은 해당 객체에 ISaveable을 구현하고 다른 클래스를 만지지 마십시오.

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

종종 인터페이스에 실현되지 않은 이점은 수정 사항을 현지화한다는 것입니다. 일단 정의되면 응용 프로그램의 전체 흐름을 거의 변경하지 않지만 종종 세부 수준에서 변경합니다. 특정 개체의 세부 정보를 유지하더라도 ProcessA의 변경 사항은 ProcessB의 변경 사항에 영향을 미치지 않습니다. (기본 수업도이 혜택을 제공합니다.)

편집 : 또 다른 이점은 행동의 특이성입니다. 내 예에서와 같이 데이터를 저장하기 만하면됩니다. 제어 유형이 무엇인지 또는 다른 작업을 수행 할 수 있는지 상관하지 않습니다. 데이터를 제어에 저장할 수 있는지 알고 싶습니다. 사용자 정의 컨트롤이 모든 것을 처리하기 때문에 텍스트, 숫자, 부울 또는 기타 여부를 확인하는 검사가 없습니다.


4

클래스의 동작을 강제해야하는 경우 인터페이스를 정의해야합니다.

동물의 행동에는 걷기, 먹기, 달리기 등이 포함될 수 있습니다. 따라서 동물을 인터페이스로 정의하십시오.

또 다른 실제 예는 ActionListener (또는 Runnable) 인터페이스입니다. 특정 이벤트를 추적해야 할 때이를 구현합니다. 따라서 actionPerformed(Event e)클래스 (또는 서브 클래스)에서 메소드 의 구현을 제공해야합니다 . 마찬가지로 Runnable 인터페이스의 경우 public void run()메소드 구현을 제공합니다 .

또한 이러한 인터페이스를 여러 클래스로 구현할 수 있습니다.

인터페이스가 Java에서 사용되는 또 다른 인스턴스는 C ++에서 제공되는 다중 상속을 구현하는 것입니다.


3
인터페이스와 관련하여 다중 상속과 같은 말을 멈추게 해주세요. 당신은 하지 마십시오 클래스에서 인터페이스를 상속합니다. 당신은 그것을 구현 합니다.
Andrei Rînea

4

잠을 자려고 할 때 발생할 수있는 성가심을 모델링하고 싶다고 가정하자.

인터페이스 전 모델

여기에 이미지 설명을 입력하십시오

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

당신이 분명히 보듯이 많은 '사물들'은 잠을 자려고 할 때 성 가실 수 있습니다.

인터페이스가없는 클래스 사용

그러나 이러한 클래스를 사용할 때 문제가 있습니다. 공통점이 없습니다. 각 메소드를 별도로 호출해야합니다.

class TestAnnoyingThings{
    void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
         if(mosquito != null){
             mosquito.flyAroundYourHead();
         }
         if(neighbour!= null){
             neighbour.startScreaming();
         }
         if(lamp!= null){
             lamp.shineJustThroughYourWindow();
         }
    }
}

인터페이스가있는 모델

이 프로브를 극복하기 위해 iterface를 도입 할 수 있습니다여기에 이미지 설명을 입력하십시오

interface Annoying{
   public void annoy();

}

그리고 클래스 내에서 구현하십시오.

class Mosquito implements Annoying {
    void flyAroundYourHead(){}

    void annoy(){
        flyAroundYourHead();
    }
}

class Neighbour implements Annoying{
    void startScreaming(){}

    void annoy(){
        startScreaming();
    }
}

class LampJustOutsideYourWindow implements Annoying{
    void shineJustThroughYourWindow() {}

    void annoy(){
        shineJustThroughYourWindow();
    }
}

인터페이스 사용

이 클래스를 훨씬 쉽게 사용할 수 있습니다.

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}

좋아,하지만하지 않습니다 NeighbourLampJustOutsideYourWindow구현해야도 Annoying?
스타 더스트

예, 지적 해 주셔서 감사합니다. 이 변경 사항으로 편집했습니다
Marcin Szymczak

2

가장 쉬운 예는 지불 처리기 (Paypal, PDS 등)입니다.

ProcessACH 및 ProcessCreditCard 메소드가있는 인터페이스 IPaymentProcessor를 작성한다고 가정하십시오.

이제 구체적인 Paypal 구현을 구현할 수 있습니다. 이러한 메소드를 작성하면 PayPal 특정 함수가 호출됩니다.

나중에 다른 공급자로 전환해야한다고 결정할 수 있습니다. 새로운 제공자를 위해 또 다른 구체적인 구현을 만드십시오. 인터페이스 (계약) 만 있으면되므로 사용하는 코드를 변경하지 않고도 응용 프로그램에서 사용하는 인터페이스를 바꿀 수 있습니다.


2

또한 모의 단위 테스트 (.Net)를 수행 할 수 있습니다. 클래스가 인터페이스를 사용하는 경우 단위 테스트에서 객체를 조롱하고 실제로 데이터베이스 나 웹 서비스에 충돌하지 않고 로직을 쉽게 테스트 할 수 있습니다.

http://www.nmock.org/


2

.NET Framework 어셈블리를 탐색하고 표준 개체에 대한 기본 클래스를 드릴 다운하면 많은 인터페이스 (ISomeName이라는 멤버)가 표시됩니다.

인터페이스는 기본적으로 크거나 작은 프레임 워크를 구현하기위한 것입니다. 내 자신의 프레임 워크를 작성하고 싶을 때까지 인터페이스에 대해 같은 방식을 느꼈습니다. 또한 인터페이스를 이해하면 프레임 워크를 훨씬 빠르게 익힐 수있었습니다. 거의 모든 것에 대해 더 우아한 솔루션을 작성하려는 순간, 인터페이스가 의미가 있다는 것을 알게 될 것입니다. 그것은 수업이 직업에 적합한 옷을 입게하는 방법과 같습니다. 더 중요한 것은 클래스가 인터페이스를 구현할 때 복잡한 객체가 덜 복잡 해져서 기능을 분류하는 데 도움이되기 때문에 인터페이스는 시스템이 훨씬 더 자체 문서화 될 수 있도록합니다.

클래스는 프레임 워크에 명시 적 또는 암시 적으로 참여할 수 있도록 인터페이스를 구현합니다. 예를 들어 IDisposable은 널리 사용되는 유용한 Dispose () 메서드에 메서드 서명을 제공하는 일반적인 인터페이스입니다. 프레임 워크에서 사용자 나 다른 개발자가 클래스에 대해 알아야 할 것은 IDisposable을 구현하면 정리 목적으로 ((IDisposable) myObject) .Dispose ()를 호출 할 수 있다는 것입니다.

기본 예 : IDisposable 인터페이스를 구현하지 않으면 C #에서 "using ()"키워드 구문을 사용할 수 없습니다. 매개 변수로 지정된 모든 개체를 암시 적으로 IDisposable로 캐스팅 할 수 있어야하기 때문입니다.

복잡한 예 :보다 복잡한 예는 System.ComponentModel.Component 클래스입니다. 이 클래스는 IDisposable과 IComponent를 모두 구현합니다. 비주얼 디자이너가 연결된 대부분의 .NET 개체는 IDE가 구성 요소와 상호 작용할 수 있도록 IComponent를 구현합니다.

결론 : .NET Framework에 익숙해 짐에 따라 Object Browser 또는 .NET Reflector (무료) 도구 ( http://www.red-gate.com )에서 새 클래스를 만날 때 가장 먼저해야 할 일 / products / reflector / )는 상속받은 클래스와 구현하는 인터페이스를 확인합니다. .NET 리플렉터는 파생 클래스를 볼 수 있기 때문에 객체 브라우저보다 훨씬 좋습니다. 이를 통해 특정 클래스에서 파생 된 모든 객체에 대해 배울 수 있으므로 존재하지 않았던 프레임 워크 기능에 대해 잠재적으로 배울 수 있습니다. 이는 업데이트되었거나 새로운 네임 스페이스가 .NET Framework에 추가 될 때 특히 중요합니다.


2

1 인칭 슈팅 게임을 만드는 것을 고려하십시오. 플레이어는 여러 총을 선택할 수 있습니다.

Gun함수를 정의 하는 인터페이스 를 가질 수 있습니다 shoot().

우리는 서로 다른 서브 클래스가 필요 Gun, 즉 클래스 ShotGun Sniper등등을.

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

슈터 클래스

범인은 그의 갑옷에 모든 총을 가지고 있습니다. List그것을 나타 내기 위해 를 만들 수 있습니다.

List<Gun> listOfGuns = new ArrayList<Gun>();

사수는 필요에 따라 기능을 사용하여 총을 순환합니다. switchGun()

public void switchGun(){
    //code to cycle through the guns from the list of guns.
    currentGun = //the next gun in the list.
}

위의 함수를 사용하여 현재 Gun을 설정하고 호출 shoot()되면 간단히 함수 를 호출 할 수 fire()있습니다.

public void fire(){
    currentGun.shoot();
}

촬영 기능의 동작은 Gun인터페이스의 구현에 따라 다릅니다 .

결론

클래스 함수가 다른 클래스의 함수에 종속되면 인터페이스를 작성합니다 . 구현 된 클래스의 인스턴스 (객체)에 따라 동작이 변경 될 수 있습니다.

예를 들어 class의 fire()함수 Shooter는 guns ( Sniper, ShotGun)가 shoot()함수 를 구현할 것으로 예상 합니다. 총을 쏴서 발사하면

shooter.switchGun();
shooter.fire();

fire()기능 의 동작을 변경했습니다 .


1

Larsenal이 말한 것을 확장합니다. 인터페이스는 모든 구현 클래스가 따라야하는 계약입니다. 이로 인해 계약 프로그래밍이라는 기술을 사용할 수 있습니다. 이를 통해 소프트웨어를 독립적으로 구현할 수 있습니다.


1

인터페이스는 일반적으로 객체가 나타낼 수있는 동작을 정의 할 때 사용됩니다.

.NET 세계에서 이에 대한 좋은 예는 IDisposable 인터페이스로, 수동으로 해제해야하는 시스템 리소스를 사용하는 모든 Microsoft 클래스에서 사용됩니다. 이를 구현하는 클래스에는 Dispose () 메서드가 있어야합니다.

(Dispose () 메소드는 VB.NETC #에 대한 언어 구성 사용으로도 호출되며 IDisposables 에서만 작동합니다. )

TypeOf ... Is(VB.NET), is(C #), instanceof(Java) 등과 같은 구문을 사용하여 개체가 특정 인터페이스를 구현하는지 확인할 수 있습니다 .


1

여러 사람들이 이미 대답했듯이 인터페이스를 사용하여 클래스 간 특정 동작을 적용하여 동일한 동작을 구현하지 않을 수 있습니다. 따라서 인터페이스를 구현함으로써 클래스의 인터페이스 동작이 있다고합니다. IAnimal 인터페이스는 Dog, Cat, Bird 등의 클래스가 동물의 유형이기 때문에 일반적인 인터페이스가 아니며 상속의 경우 확장해야합니다. 대신이 경우 인터페이스는 IRunnable, IFlyable, ITrainable 등과 같은 동물 행동과 유사합니다.

인터페이스는 많은 것들에 좋으며, 중요한 것 중 하나는 플러그 가능성입니다. 예를 들어 List 매개 변수가있는 메서드를 선언하면 List 인터페이스를 구현하는 모든 항목을 전달할 수 있으므로 개발자는 많은 코드를 다시 작성하지 않고도 나중에 다른 목록을 제거하고 연결할 수 있습니다.

인터페이스를 사용하지 않을 수도 있지만 처음부터 프로젝트, 특히 일종의 프레임 워크를 디자인하는 경우 친숙해지기를 원할 것입니다.

Coad, Mayfield 및 Kern의 Java Design 인터페이스에 대한 장을 읽는 것이 좋습니다 . 그들은 평균 입문 텍스트보다 조금 더 잘 설명합니다. Java를 사용하지 않는 경우, 주로 개념 인 장의 시작 부분을 읽을 수 있습니다.


1

시스템에 유연성을 추가하는 프로그래밍 기술로서 인터페이스도 다소 복잡성을 가중시킵니다. 그것들은 종종 훌륭하고 어디서나 사용할 수 있습니다 (모든 클래스에 대한 인터페이스를 만들 수 있습니다). 그러나 그렇게하면 유지하기가 더 복잡한 더 복잡한 시스템을 만들 수 있습니다.

여기에는 평소와 같이 절충점이 있습니다 : 유지 관리성에 대한 유연성. 어느 것이 더 중요합니까? 답이 없습니다-프로젝트에 따라 다릅니다. 그러나 모든 소프트웨어는 유지 관리해야합니다 ...

그래서 내 충고 : 정말 필요할 때까지 인터페이스를 사용하지 마십시오. (Visual Studio를 사용하면 2 초 안에 기존 클래스에서 인터페이스를 추출 할 수 있으므로 서두르지 마십시오.)

당신은 언제 인터페이스를 만들어야합니까?

갑자기 두 개 이상의 유사한 클래스를 처리 해야하는 메소드를 리팩토링 할 때 수행합니다 . 그런 다음 인터페이스를 만들고이 인터페이스를 두 개 이상의 유사한 클래스에 할당하고 메서드 매개 변수 유형을 변경합니다 (클래스 유형을 인터페이스 유형으로 바꿉니다).

그리고 그것은 작동합니다 : o)

한 가지 예외 : 객체를 조롱 할 때 인터페이스가 훨씬 더 사용하기 쉽습니다. 그래서 나는 종종 이것을 위해 인터페이스를 만듭니다.

추신 : "인터페이스"를 작성할 때 순수한 인터페이스 클래스를 포함한 "모든 기본 클래스의 인터페이스"를 의미합니다. 추상 클래스는 로직을 추가 할 수 있기 때문에 순수한 인터페이스보다 더 나은 방법입니다.

감사합니다, 실뱅


1

라이브러리 개발자 (다른 코더를 코딩하는 사람) 가되면 인터페이스가 분명해 집니다. 우리 대부분은 기존 API 및 프로그래밍 라이브러리를 사용하는 응용 프로그램 개발자 로 시작합니다 .

Interfaces가 계약 과 동일한 행을 따라 아직 아무도 Interfaces가 코드의 일부를 안정적 으로 만드는 좋은 방법이라고 언급하지 않았습니다 . 프로젝트 일 때 (또는 다른 개발자가 사용하는 코드를 개발할 때) 특히 유용합니다 . 따라서 구체적인 시나리오는 다음과 같습니다.

에서 코드를 개발할 때 다른 사람들이 작성한 코드를 사용하고있을 수 있습니다. 그들은 (안정적인) 인터페이스로 코딩 할 때 가장 기뻐할 것이며, 팀의 코드를 손상시키지 않고 구현 (인터페이스 뒤에 숨겨져 있음)을 자유롭게 변경할 수 있다면 기쁠 것입니다. 정보 숨기기 의 변형입니다 (인터페이스는 공개되고 구현은 클라이언트 프로그래머에게 숨겨져 있습니다). 보호 변형 에 대해 자세히 알아보십시오 .

또한 인터페이스 코딩에 대한관련 질문을 참조하십시오 .


1

인터페이스를 사용하는 데는 많은 목적이 있습니다.

  1. 다형성 행동에 사용하십시오. 하위 클래스에 대한 참조가있는 인터페이스를 사용하여 하위 클래스의 특정 메소드를 호출하려는 경우

  2. 가장 일반적인 용도와 같이 COM과 함께 클래스와 계약을 맺으면 인터페이스를 상속하는 DLL에서 래퍼 클래스가 생성됩니다. 이러한 메소드는이면에서 호출되며 COM DLL에 정의 된 것과 동일한 구조로 구현해야하지만 노출되는 인터페이스를 통해서만 알 수 있습니다.

  3. 클래스에 특정 메소드를로드하여 메모리 사용량을 줄입니다. 세 개의 비즈니스 오브젝트가 있고 단일 클래스로 구현 된 것처럼 세 개의 인터페이스를 사용할 수 있습니다.

예 : IUser, IOrder, IOrderItem

public interface IUser()
{

void AddUser(string name ,string fname);

}

// Same for IOrder and IOrderItem
//


public class  BusinessLayer: IUser, IOrder, IOrderItem

{    
    public void AddUser(string name ,string fname)
    {
        // Do stuffs here.
    }

    // All methods from all interfaces must be implemented.

}

사용자 만 추가하려면 다음과 같이하십시오.

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

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