“인터페이스 프로그래밍”이란 무엇입니까?


813

나는 이것이 몇 번 언급 된 것을 보았고 그것이 무엇을 의미하는지 명확하지 않다. 언제, 왜 이렇게 하시겠습니까?

나는 인터페이스가 무엇을하는지 알고 있지만, 이것에 대해 명확하지 않다는 사실은 내가 올바르게 사용하는데 빠졌다고 생각합니다.

당신이해야한다면 그냥 그렇습니까?

IInterface classRef = new ObjectWhatever()

구현하는 클래스를 사용할 수 IInterface있습니까? 언제해야합니까? 내가 생각할 수있는 유일한 것은 메소드가 있고 구현을 제외하고 어떤 오브젝트가 전달 될지 확신 할 수없는 경우입니다 IInterface. 얼마나 자주 그렇게해야하는지 생각할 수 없습니다.

또한 인터페이스를 구현하는 객체를 취하는 메소드를 어떻게 작성할 수 있습니까? 가능합니까?


3
기억하고 프로그램을 최적화해야하는 경우 컴파일 직전에 실제 구현을 위해 인터페이스 선언을 교체 할 수 있습니다. 인터페이스를 사용하면 간접적 인 수준이 추가되어 성능이 저하됩니다. 그래도 인터페이스에 프로그래밍 된 코드를 배포하십시오.
Ande Turner

18
@Ande Turner : 좋지 않은 조언입니다. 1). "프로그램이 최적이어야합니다"는 인터페이스를 교체하는 좋은 이유가 아닙니다! 그런 다음 "하지만 프로그래밍 된 코드를 인터페이스에 배포하십시오 ..."라고 말하면 주어진 요구 사항을 조언하는 것입니다. (1) 차선책 코드를 해제 하시겠습니까?!?
Mitch Wheat

74
여기에있는 대부분의 답변이 옳지 않습니다. "인터페이스 키워드 사용"을 의미하거나 암시하지도 않습니다. 인터페이스는 무언가를 사용하는 방법에 대한 사양으로, 계약과 동의어입니다 (찾아보십시오). 그와 별개로 구현은 계약이 이행되는 방식입니다. 메소드 / 유형이 계약에 여전히 순종하는 방식으로 변경 될 때이를 사용하여 코드를 위반하지 않도록 메소드 / 유형의 보장에 대해서만 프로그램하십시오.
jyoungdev

2
@ apollodude217은 실제로 전체 페이지에서 가장 좋은 답변입니다. 여기에 적어도 3 가지의 다른 질문이 있기 때문에 제목에있는 질문에 대해 적어도…
Andrew Spencer

4
이와 같은 질문에 대한 근본적인 문제는 "인터페이스로 프로그래밍하는"은 "모든 것을 추상 인터페이스로 랩핑"하는 것을 의미한다고 가정하는데, 용어가 Java 스타일 추상 인터페이스의 개념보다 이전의 용어를 고려한다면 어리석은 일입니다.
Jonathan Allen

답변:


1633

이 질문에 대한 인터페이스에는 인터페이스와 느슨하게 결합 된 코드, 제어 반전 등에 대한 모든 종류의 세부 정보가 들어 있습니다. 상당히 까다로운 토론이 있으므로 인터페이스가 유용한 이유를 이해하기 위해 약간의 문제를 해결하고 싶습니다.

처음 인터페이스에 노출되기 시작했을 때 나는 그들의 관련성에 대해 혼란 스러웠다. 왜 당신이 그것들을 필요로하는지 이해하지 못했습니다. Java 또는 C #과 같은 언어를 사용하는 경우 이미 상속을 받았으며 인터페이스를 더 약한 상속 형식으로보고 "왜 귀찮게합니까?" 내가 옳다는 의미에서, 당신은 인터페이스를 일종의 약한 상속 형태로 생각할 수 있지만, 그 이상으로 공통된 특성이나 행동을 분류하는 수단으로 생각하여 언어 구성으로 사용하는 것을 마침내 이해했습니다. 잠재적으로 많은 관련이없는 객체 클래스.

예를 들어-SIM 게임이 있고 다음과 같은 클래스가 있다고 가정하십시오.

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

분명히이 두 객체는 ​​직접 상속 측면에서 공통점이 없습니다. 그러나 둘 다 성가 신다고 말할 수 있습니다.

우리 게임에는 저녁을 먹을 때 게임 플레이어를 괴롭히는 일종의 임의의 것이 필요하다고 가정 해 봅시다 . 이것은 HouseFly하나 Telemarketer또는 둘 다일 수 있지만 단일 함수로 두 가지를 어떻게 허용합니까? 서로 다른 유형의 객체에 같은 방식으로 "성가신 일을"하도록 요청하는 방법

인식의 핵심 은 모델링과 관련하여 아무것도 같지 않지만 공통적으로 느슨하게 해석되는 동작을 공유 Telemarketer하고 HouseFly공유한다는 것입니다. 따라서 둘 다 구현할 수있는 인터페이스를 만들어 봅시다.

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

우리는 이제 각자 자신의 방식으로 성가 시게 할 수있는 두 개의 클래스를 가지고 있습니다. 그리고 그들은 동일한 기본 클래스에서 파생 할 필요가없고 공통 계약을 충족시킬 필요가있는 공통의 고유 특성을 공유 할 필요가 없습니다 IPest. 당신은 단지해야합니다 BeAnnoying. 이와 관련하여 다음을 모델링 할 수 있습니다.

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

여기에는 많은 식당과 해충을 수용하는 식당이 있습니다. 인터페이스 사용에 주목하십시오. 이것은 우리의 작은 세계에서 pests배열 의 구성원 이 실제로 Telemarketer객체 또는 객체 가 될 수 있음을 의미 HouseFly합니다.

ServeDinner방법은 저녁 식사가 제공되고 식당에있는 사람들이 먹어야 할 때 호출됩니다. 우리의 작은 게임에서, 그것은 우리의 해충이 일을 할 때입니다-각 해충은 IPest인터페이스 를 통해 성가 시도록 지시받습니다 . 이러한 방법으로, 우리는 쉽게 모두를 가질 수 TelemarketersHouseFlys자신의 방법으로 각 성가신 일 - 우리는 우리가 뭔가 가지고에만 신경 DiningRoom해충이다 오브젝트를, 우리는 정말 그것이 무엇인지 상관 없어 그들은에서 아무것도 할 수 다른 사람과 공통입니다.

이 매우 고안된 의사 코드 예제 (예상보다 훨씬 길게 드래그 한 것)는 단순히 인터페이스를 사용할 때의 관점에서 마지막으로 불이 켜진 종류를 설명하기위한 것입니다. 나는이 예의 어리 석음에 대해 미리 사과하지만 그것이 이해하는 데 도움이되기를 바랍니다. 그리고 확실히, 여기에 당신이받은 다른 게시물 답변은 오늘날 디자인 패턴 및 개발 방법론에서 인터페이스를 사용하는 영역을 다루고 있습니다.


3
고려해야 할 또 다른 사항은 어떤 경우에는 "성가신"성가신 것들에 대한 인터페이스를 갖는 것이 유용 할 수 있으며, 다양한 객체 BeAnnoying가 no-op으로 구현 되도록하는 것입니다. 이 인터페이스는 대신에 존재하거나 짜증나는 것들에 대한 인터페이스에 추가 (두 인터페이스가 존재하는 경우 "일 수 있습니다 짜증나는"인터페이스는 "일에서 상속해야합니다 수 있습니다 인터페이스 짜증나"). 이러한 인터페이스를 사용하는 단점은 구현이 "성가신"수의 스텁 메소드를 구현하는 데 부담을 줄 수 있다는 것입니다. 장점은 ...
supercat

4
이 메소드는 추상 메소드를 나타 내기위한 것이 아니며 구현은 인터페이스에 중점을 둔 질문과 관련이 없습니다.
Peter Meyer

33
IPest와 같은 행동을 캡슐화하는 것은 누군가가 그 주제에 대해 더 많은 자료를 추적하는 데 관심이있는 경우를 대비하여 전략 패턴으로 알려져 있습니다.
nckbrz

9
흥미롭게 IPest[]도 IPest 참조 의 객체 는 IPest 참조 BeAnnoying()이기 때문에 해당 메소드가 있기 때문에 호출 할 수 있지만 캐스트없이 다른 메소드를 호출 할 수는 없습니다. 그러나 각 객체마다 개별 BeAnnoying()메소드가 호출됩니다.
D. Ben Knoble 1

4
아주 좋은 설명 ... 그냥 여기에 말할 필요 가 있습니다. 인터페이스가 느슨한 상속 메커니즘이라는 것을 들어 본 적이 없지만 대신 인터페이스를 정의하기위한 가난한 메커니즘으로 상속이 사용되는 것을 알고 있습니다 (예 : 일반 Python에서 항상해라).
카를로스 H 로마노

282

내가 학생들에게 줄 때 사용한 구체적인 예는

List myList = new ArrayList(); // programming to the List interface

대신에

ArrayList myList = new ArrayList(); // this is bad

이것들은 짧은 프로그램에서 정확히 똑같아 보이지만 프로그램에서 myList100 번 계속 사용 하면 차이를 볼 수 있습니다. 첫 번째 선언은 인터페이스에 myList의해 정의 된 메소드 만 호출 List하므로 ArrayList특정 메소드 는 호출 하지 않습니다 . 이 방법으로 인터페이스에 프로그래밍 한 경우 나중에 실제로 필요한 것으로 결정할 수 있습니다

List myList = new TreeList();

한 지점에서만 코드를 변경하면됩니다. 이미 인터페이스에 프로그래밍했기 때문에 구현의 변경으로 인해 코드의 나머지 부분이 손상되지 않는다는 것을 이미 알고 있습니다 .

메소드 매개 변수와 반환 값에 대해 이야기 할 때 이점이 훨씬 분명합니다. 예를 들면 다음과 같습니다.

public ArrayList doSomething(HashMap map);

이 메소드 선언은 두 가지 구체적인 구현 ( ArrayListHashMap)에 연결됩니다. 해당 메소드가 다른 코드에서 호출되는 즉시 해당 유형이 변경되면 호출 코드도 변경해야합니다. 인터페이스에 프로그래밍하는 것이 좋습니다.

public List doSomething(Map map);

이제 어떤 종류의 List리턴인지, 어떤 종류의 Map매개 변수로 전달 되는지 는 중요하지 않습니다 . doSomething메소드 내에서 변경하면 호출 코드를 변경하지 않아도됩니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Yvette

매우 명확한 설명. 매우 유용
samuel luswata

"첫 번째 선언은 List 인터페이스에 의해 정의 된 myList의 메소드 만 호출하도록합니다 (따라서 ArrayList 특정 메소드는 없습니다). 이런 식으로 인터페이스에 프로그래밍 한 경우 나중에 "List myList = new TreeList ();가 정말로 필요하다고 결정할 수 있으며, 한 지점에서만 코드를 변경하면됩니다." 어쩌면 내가 잘못 이해했을 수도 있습니다. "myList에서 메소드 만 호출하도록하려면"왜 ArrayList를 TreeList로 변경해야하는지 궁금합니다.
user3014901

1
@ user3014901 사용중인 목록 유형을 변경하려는 이유는 여러 가지가 있습니다. 예를 들어 조회 성능이 향상 될 수 있습니다. 요점은 List 인터페이스에 프로그래밍하면 나중에 다른 구현으로 코드를 쉽게 변경할 수 있다는 것입니다.
Bill the Lizard

73

인터페이스 프로그래밍은 "이 기능이 필요하며 그것이 어디에서 왔는지 상관하지 않습니다."라고 말합니다.

(자바에서는) List인터페이스 ArrayListLinkedList구체적인 클래스를 고려하십시오 . 내가 관심있는 모든 것이 반복을 통해 액세스 해야하는 여러 데이터 항목을 포함하는 데이터 구조를 가지고 있다는 것이라면 List(그리고 99 %의 시간)을 선택합니다. 목록의 양쪽 끝에서 일정한 시간 삽입 / 삭제가 필요하다는 것을 알고 있다면 LinkedList구체적인 구현을 선택 하거나 대기열 인터페이스를 사용할 가능성이 큽니다 . 인덱스별로 임의 액세스가 필요하다는 것을 알고 있다면 ArrayList구체적인 클래스를 선택합니다 .


1
즉, 수행 된 작업과 수행 된 작업 간의 독립성에 전적으로 동의합니다. 독립적 인 구성 요소에 따라 시스템을 분할하여 (참조 간단하고 재사용하는 시스템으로 끝날 간단한 제작 쉬운 Clojure를 만든 사람에 의해)
beluchin

38

인터페이스를 사용하면 클래스 간의 불필요한 커플 링을 제거 할뿐만 아니라 코드를 쉽게 테스트 할 수있는 핵심 요소가됩니다. 클래스에서 작업을 정의하는 인터페이스를 만들면 해당 기능을 사용하려는 클래스가 구현 클래스에 직접 의존하지 않고 해당 기능을 사용할 수 있습니다. 나중에 다른 구현을 변경하고 사용하기로 결정한 경우 구현이 인스턴스화되는 코드 부분 만 변경하면됩니다. 코드의 나머지 부분은 구현 클래스가 아닌 인터페이스에 의존하기 때문에 변경할 필요가 없습니다.

이것은 단위 테스트를 만드는 데 매우 유용합니다. 테스트중인 클래스에서 인터페이스에 의존하고 생성자 또는 속성 설정자를 통해 인터페이스 인스턴스를 클래스 (또는 필요에 따라 인터페이스 인스턴스를 빌드 할 수있는 팩토리)에 주입합니다. 클래스는 메소드에서 제공된 (또는 작성된) 인터페이스를 사용합니다. 테스트를 작성하려고 할 때 인터페이스를 조롱하거나 위조하고 단위 테스트에서 구성된 데이터로 응답하는 인터페이스를 제공 할 수 있습니다. 테스트중인 클래스는 구체적인 구현이 아닌 인터페이스 만 다루기 때문에이 작업을 수행 할 수 있습니다. 모의 또는 가짜 클래스를 포함하여 인터페이스를 구현하는 모든 클래스가 수행합니다.

편집 : 아래는 Erich Gamma가 자신의 인용문 "구현이 아닌 인터페이스에 대한 프로그램"을 설명하는 기사에 대한 링크입니다.

http://www.artima.com/lejava/articles/designprinciples.html


3
이 인터뷰를 다시 읽어보십시오. Gamma는 물론 JAVA 또는 C # 특수 클래스 (ISomething)가 아닌 인터페이스의 OO 개념에 대해 이야기하고있었습니다. 문제는 대부분의 사람들이 키워드에 대해 이야기하고 있었기 때문에 원하지 않는 인터페이스 (ISomething)가 많이 있다는 것입니다.
Sylvain Rodrigue

아주 좋은 인터뷰. 장래 독자들을 위해 조심하십시오, 인터뷰에는 4 페이지가 있습니다. 나는 그것을보기 전에 브라우저를 거의 닫을 것입니다.
Ad Infinitum

37

인터페이스 프로그래밍은 Java 또는 .NET에서 볼 수있는 것처럼 추상 인터페이스와 전혀 관련이 없습니다. 심지어 OOP 개념이 아닙니다.

의미하는 것은 객체 또는 데이터 구조의 내부를 어지럽히 지 않습니다. 데이터와 상호 작용하려면 추상 프로그램 인터페이스 또는 API를 사용하십시오. Java 또는 C #에서는 원시 필드 액세스 대신 공용 특성 및 메소드를 사용합니다. C의 경우 원시 포인터 대신 함수를 사용하는 것을 의미합니다.

편집 : 데이터베이스를 사용하면 직접 테이블 액세스 대신 뷰 및 저장 프로 시저를 사용하는 것이 좋습니다.


5
가장 좋은 답변입니다. 감마는 여기에 유사한 설명을 제공합니다 : artima.com/lejava/articles/designprinciples.html (페이지 2). 그는 OO 개념을 언급하고 있지만 당신 말이 맞습니다. 그것은 그것보다 큽니다.
Sylvain Rodrigue

36

Inversion of Control을 살펴 봐야합니다.

이러한 시나리오에서는 다음과 같이 쓰지 않습니다.

IInterface classRef = new ObjectWhatever();

다음과 같이 작성하십시오.

IInterface classRef = container.Resolve<IInterface>();

이것은 container객체 의 규칙 기반 설정으로 들어가서 실제 객체를 생성합니다. ObjectWhatever가 될 수 있습니다. 중요한 것은이 규칙을 다른 유형의 객체를 모두 사용하는 것으로 대체 할 수 있으며 코드가 여전히 작동한다는 것입니다.

IoC를 테이블에서 분리하면 특정 유형의 객체 또는 객체 유형이 아닌 객체와 통신 할 수 있다는 것을 알고있는 코드를 작성할 수 있습니다 .

매개 변수를 전달할 때 유용합니다.

괄호로 묶인 질문에 관해서는 "또한 인터페이스를 구현하는 객체를 취하는 메소드를 어떻게 작성할 수 있습니까? 가능합니까?", C #에서는 다음과 같이 매개 변수 유형에 대한 인터페이스 유형을 간단히 사용합니다.

public void DoSomethingToAnObject(IInterface whatever) { ... }

이것은 "특정한 일을하는 객체와 대화"에 바로 연결됩니다. 위에서 정의한 방법은 객체에서 무엇을 기대해야하는지 알고, IInterface의 모든 것을 구현하지만, 객체의 유형을 신경 쓰지 않고 계약을 준수하는 것만 신경 쓰면됩니다.

예를 들어, 당신은 아마도 계산기에 익숙하고 아마 당신의 하루에 꽤 며칠을 사용했을 것입니다. 그러나 대부분의 시간은 모두 다릅니다. 반면에 표준 계산기의 작동 방식을 알고 있으므로 각 계산기에 다른 기능이없는 특정 기능을 사용할 수없는 경우에도 모두 사용할 수 있습니다.

이것이 인터페이스의 아름다움입니다. 특정 동작을 기대할 수있는 객체가 전달 될 것이라는 것을 알고있는 코드를 작성할 수 있습니다. 어떤 종류의 객체인지는 신경 쓰지 않고 필요한 동작을 지원합니다.

구체적인 예를 들어 보겠습니다.

우리는 Windows 양식을위한 맞춤형 번역 시스템을 가지고 있습니다. 이 시스템은 폼의 컨트롤을 반복하고 각 텍스트를 번역합니다. 이 시스템은 텍스트 속성이있는 컨트롤 유형 및 이와 유사한 기본 항목과 같은 기본 컨트롤을 처리하는 방법을 알고 있지만 기본적인 사항은 부족합니다.

이제 컨트롤은 제어 할 수없는 미리 정의 된 클래스에서 상속되므로 다음 세 가지 중 하나를 수행 할 수 있습니다.

  1. 번역 시스템에 대한 지원을 구축하여 작업중인 제어 유형을 구체적으로 감지하고 올바른 비트를 번역합니다 (유지 관리 악몽).
  2. 기본 클래스에 대한 지원 구축 (모든 컨트롤이 미리 정의 된 다른 클래스에서 상속되므로 불가능)
  3. 인터페이스 지원 추가

그래서 우리는 nr을했다. 3. 모든 컨트롤은 "자체"를 번역 텍스트 / 규칙 컨테이너로 번역 할 수있는 기능인 ILocalizable을 구현합니다. 따라서 폼은 어떤 종류의 컨트롤을 찾았는지 알 필요가 없으며 특정 인터페이스를 구현하고 컨트롤을 지역화하기 위해 호출 할 수있는 메서드가 있다는 것을 알고 있습니다.


31
처음부터 IoC를 언급하는 이유는 더 혼란 스러울뿐입니다.
Kevin Le-Khnle

1
동의합니다. 인터페이스에 대한 프로그래밍은 IoC를보다 쉽고 안정적으로 만드는 기술 일뿐입니다.
terjetyl

28

인터페이스에 대한 코드 구현이 Java와 관련이 없으며 인터페이스 구성도 아닙니다.

이 개념은 Patterns / Gang of Four 서적에서 두드러졌지만, 아마도 그보다 훨씬 이전에 있었을 것입니다. 이 개념은 Java가 존재하기 전에 확실히 존재했습니다.

Java Interface 구문은이 아이디어를 돕기 위해 만들어졌으며, 사람들은 원래 의도가 아니라 의미의 중심 인 구문에 너무 집중했습니다. 그러나 Java, C ++, C # 등의 공개 및 개인 메소드 및 속성이있는 이유입니다.

그것은 단지 객체 또는 시스템의 공용 인터페이스와 상호 작용한다는 것을 의미합니다. 내부적으로 수행하는 방식에 대해 걱정하거나 예상하지 마십시오. 그것이 어떻게 구현되는지 걱정하지 마십시오. 객체 지향 코드에서는 공개 대 개인 메소드 / 속성이있는 이유입니다. 비공개 메소드는 클래스 내에서 내부 용으로 만 사용되므로 공개 메소드를 사용하려고합니다. 클래스의 구현을 구성하며 공용 인터페이스를 변경하지 않고 필요에 따라 변경할 수 있습니다. 기능과 관련하여 클래스의 메소드는 동일한 매개 변수로 호출 할 때마다 동일한 예상 결과로 동일한 조작을 수행한다고 가정하십시오. 이를 통해 저자는 사람들이 클래스와 상호 작용하는 방식을 방해하지 않고 클래스 작동 방식, 구현 방식을 변경할 수 있습니다.

또한 Interface 구문을 사용하지 않고도 구현이 아닌 인터페이스로 프로그래밍 할 수 있습니다. C ++에서 구현이 아닌 인터페이스로 프로그래밍 할 수 있으며, 인터페이스 구성이 없습니다. 두 개의 대규모 엔터프라이즈 시스템이 시스템 내부의 객체에서 메소드를 호출하는 대신 공용 인터페이스 (계약)를 통해 상호 작용하는 한 훨씬 더 강력하게 통합 할 수 있습니다. 인터페이스는 동일한 입력 매개 변수가 주어지면 항상 동일한 예상 방식으로 반응합니다. 인터페이스가 아닌 구현으로 구현 된 경우 이 개념은 여러 곳에서 작동합니다.

Java 인터페이스에는 '구현이 아닌 인터페이스에 대한 프로그램'이라는 개념과 관련이 있다는 생각을 떨치십시오. 개념을 적용하는 데 도움이 될 수 있지만 개념은 아닙니다 .


1
첫 번째 문장이 다 나와 있습니다. 이것이 정답입니다.
madumlao

14

인터페이스의 작동 방식을 이해하지만 사용시기와 인터페이스의 이점을 잘 모르는 것 같습니다. 다음은 인터페이스가 의미가있는 몇 가지 예입니다.

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

그런 다음 GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider 등을 만들 수 있습니다.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

그런 다음 JpegImageLoader, GifImageLoader, PngImageLoader 등을 만듭니다.

대부분의 애드 인 및 플러그인 시스템은 인터페이스에서 작동합니다.

다른 인기있는 용도는 리포지토리 패턴입니다. 다른 소스에서 우편 번호 목록을로드하고 싶다고 가정 해보십시오.

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

그런 다음 XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository 등을 만들 수 있습니다. 웹 응용 프로그램의 경우 종종 XML 리포지토리를 만들어 SQL 데이터베이스가 준비되기 전에 무언가를 준비하고 실행할 수 있습니다. 데이터베이스가 준비되면 XML 버전을 대체 할 SQLRepository를 작성합니다. 내 코드의 나머지 부분은 인터페이스에서만 실행되므로 변경되지 않습니다.

메소드는 다음과 같은 인터페이스를 승인 할 수 있습니다.

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

10

비슷한 클래스 세트가 있으면 코드를 훨씬 확장 가능하고 유지 관리하기가 쉽습니다. 저는 주니어 프로그래머이므로 전문가는 아니지만 비슷한 것을 요구하는 프로젝트를 마쳤습니다.

의료 기기를 실행하는 서버와 통신하는 클라이언트 측 소프트웨어에서 작업합니다. 고객이 때때로 구성해야하는 새로운 구성 요소가 포함 된이 버전의이 장치를 개발 중입니다. 새로운 구성 요소에는 두 가지 유형이 있으며 서로 다르지만 매우 유사합니다. 기본적으로 두 가지 구성 양식, 두 개의 목록 클래스, 두 가지 모두를 만들어야했습니다.

나는 거의 모든 실제 로직을 보유 할 각 제어 유형에 대한 추상 기본 클래스를 작성하고 두 구성 요소 간의 차이점을 처리하기 위해 파생 된 유형을 작성하는 것이 최선이라고 결정했습니다. 그러나 기본 클래스는 항상 유형에 대해 걱정 해야하는 경우 이러한 구성 요소에 대한 작업을 수행 할 수 없었습니다 (글쎄, 가질 수는 있지만 모든 방법에 "if"문이나 스위치가 있었을 것입니다) .

이러한 구성 요소에 대한 간단한 인터페이스를 정의했으며 모든 기본 클래스가이 인터페이스와 통신합니다. 이제 무언가를 변경하면 거의 모든 곳에서 '작동합니다'. 코드 복제가 없습니다.


9

거기에 많은 설명이 있지만 더 간단하게 만듭니다. 예를 들어 a List. 다음과 같이 목록을 구현할 수 있습니다.

  1. 내부 배열
  2. 연결리스트
  3. 다른 구현들

인터페이스를 구축하여이라고 말합니다 List. List의 정의 또는 List실제 의미에 대해서만 코딩 합니다.

내부적으로 구현이라고하는 모든 유형의 구현을 사용할 수 있습니다 array. 그러나 어떤 이유로 버그 또는 성능과 같은 구현을 변경한다고 가정하십시오. 그런 다음 선언 List<String> ls = new ArrayList<String>()을 로 변경해야 합니다 List<String> ls = new LinkedList<String>().

코드의 다른 곳에서는 다른 것을 변경해야합니다. 그 밖의 모든 것은의 정의에 따라 작성 되었기 때문입니다 List.


8

Java로 프로그래밍하는 경우 JDBC가 좋은 예입니다. JDBC는 인터페이스 세트를 정의하지만 구현에 대해서는 아무 것도 말하지 않습니다. 이 인터페이스 세트에 대해 애플리케이션을 작성할 수 있습니다. 이론적으로 JDBC 드라이버를 선택하면 응용 프로그램이 작동합니다. 더 빠르거나 "더 나은"JDBC 드라이버가 있거나 어떤 이유로 든 발견되는 경우 이론적으로 속성 파일을 다시 구성 할 수 있으며 응용 프로그램을 변경하지 않고도 응용 프로그램이 계속 작동합니다.


더 나은 드라이버를 사용할 수있는 경우에 유용 할뿐만 아니라 데이터베이스 공급 업체를 완전히 변경할 수 있습니다.
Ken Liu

3
JDBC가 너무 나빠 교체해야합니다. 다른 예를 찾으십시오.
Joshua

JDBC는 좋지 않지만 인터페이스 대 구현 또는 추상화 수준과 관련이 없습니다. 따라서 문제의 개념을 설명하기 위해 완벽합니다.
Erwin Smout

8

인터페이스 프로그래밍은 훌륭합니다. 느슨한 결합을 촉진합니다. @lassevk가 언급했듯이 Inversion of Control은 이것을 많이 사용합니다.

또한 SOLID 주체를 살펴보십시오 . 여기 비디오 시리즈가 있습니다

하드 코딩 된 (강하게 결합 된 예제)을 거친 다음 인터페이스를보고 마침내 IoC / DI 도구 (NInject)로 진행합니다.


7

나는이 질문에 늦었지만, 여기서는 "구현이 아닌 인터페이스로의 프로그램"라인이 GoF (Gang of Four) 디자인 패턴 책에서 좋은 토론을했다고 언급하고 싶다.

그것은 p. 18 :

구현이 아닌 인터페이스로 프로그램

변수를 특정 구체적 클래스의 인스턴스로 선언하지 마십시오. 대신 추상 클래스로 정의 된 인터페이스에만 커밋하십시오. 이 책에서이 디자인 패턴의 공통 주제를 찾을 수 있습니다.

그리고 그 이상으로 시작되었습니다.

추상 클래스로 정의 된 인터페이스 측면에서만 객체를 조작하면 두 가지 이점이 있습니다.

  1. 클라이언트가 기대하는 인터페이스를 객체가 준수하는 한 클라이언트는 사용하는 특정 유형의 객체를 알지 못합니다.
  2. 클라이언트는 이러한 객체를 구현하는 클래스를 알지 못합니다. 클라이언트는 인터페이스를 정의하는 추상 클래스에 대해서만 알고 있습니다.

다시 말해, 클래스 (또는 서브 클래스)의 특정 구현에 너무 구체적이기 때문에 quack()오리 bark()용 메소드와 개용 메소드를 갖도록 클래스를 작성하지 마십시오 . 대신 기본 클래스에서 사용하기에 충분한 일반적인 이름 (예 : giveSound()or move())을 사용하여 메소드를 작성하십시오 . 그래야 오리, 개 또는 심지어 자동차에 사용될 수 있으며 클래스의 클라이언트가 .giveSound()아니라 객체에 보낼 올바른 메시지를 발행하기 전에 유형 을 사용 quack()할지 bark()또는 결정 할지에 대해 생각 합니다.


6

이미 선택된 답변과 다양한 정보 게시물 외에도 Head First Design Patterns 사본을 얻는 것이 좋습니다 . 매우 쉽게 읽을 수 있으며 질문에 직접 대답하고 중요한 이유를 설명하며 해당 원리 (및 기타)를 사용하는 데 사용할 수있는 많은 프로그래밍 패턴을 보여줍니다.


5

기존 게시물에 추가하기 위해 때때로 인터페이스 코딩은 개발자가 별도의 구성 요소를 동시에 작업 할 때 대규모 프로젝트에서 도움이됩니다. 다른 개발자가 구현중인 인터페이스에 코드를 작성하는 동안 인터페이스를 미리 정의하고 코드를 작성하면됩니다.


4

또한 단위 테스팅에 유용합니다. 인터페이스의 요구 사항을 충족하는 클래스를 종속 클래스에 주입 할 수 있습니다.


4

추상화에 의존하지 않더라도 인터페이스에 프로그래밍하는 것이 유리할 수 있습니다.

인터페이스 프로그래밍 은 문맥 상 적절한 객체 서브 세트를 사용하도록 강요합니다 . 그것은 그것이 도움이되기 때문에 :

  1. 문맥 상 부적절한 행동을하지 못하게하고
  2. 향후 구현을 안전하게 변경할 수 있습니다.

예를 들어, 및 인터페이스 Person를 구현 하는 클래스를 고려하십시오 .FriendEmployee

class Person implements AbstractEmployee, AbstractFriend {
}

사람의 생일과 관련하여, 우리 Friend는 사람을 치료하는 것을 막기 위해 인터페이스로 프로그램 합니다 Employee.

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

개인의 작업 맥락에서, 우리는 Employee직장 경계가 흐려지는 것을 방지하기 위해 인터페이스로 프로그래밍 합니다.

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

큰. 우리는 서로 다른 상황에서 적절하게 행동했으며 소프트웨어가 잘 작동하고 있습니다.

장래에, 우리의 사업이 개와 함께 작동하도록 변경되면 소프트웨어를 상당히 쉽게 변경할 수 있습니다. 먼저 와를 Dog모두 구현 하는 클래스를 만듭니다 . 그런 다음 안전하게로 변경 합니다 . 두 함수 모두 수천 줄의 코드를 가지고 있더라도 다음과 같은 사실을 알고 있기 때문에 간단한 편집이 가능합니다.FriendEmployeenew Person()new Dog()

  1. 함수 party는의 Friend하위 집합 만 사용합니다 Person.
  2. 함수 workplace는의 Employee하위 집합 만 사용합니다 Person.
  3. 클래스 Dog는 인터페이스 FriendEmployee인터페이스를 모두 구현합니다 .

반면에 party또는 workplace에 대해 프로그래밍 Person한 경우 Person특정 코드 가있을 위험이 있습니다 . 에서 Person로 변경하면 지원되지 않는 특정 코드 Dog를 없애기 위해 코드를 훑어보아야합니다 .PersonDog

도덕 : 인터페이스 프로그래밍은 코드가 적절하게 작동하고 변경 준비를하는 데 도움이됩니다. 또한 추상화에 의존하도록 코드를 준비하여 더 많은 이점을 제공합니다.


1
지나치게 넓은 인터페이스가 없다고 가정하면, 즉.
Casey

4

Swimmer기능을 추가하기 위해 새 클래스 를 작성 swim()중이고 say 클래스의 객체를 사용해야하는 Dog경우이 Dog클래스 Animal는를 선언 하는 인터페이스 를 구현 합니다 swim().

계층 구조 ( Animal) 의 맨 위에는 매우 추상적 인 반면 맨 아래 ( Dog)에는 매우 구체적입니다. "인터페이스 프로그래밍"에 대해 생각하는 방식은 Swimmer클래스를 작성할 때이 경우 Animal객체 인 계층 구조까지 인터페이스에 대해 코드를 작성하려고한다는 것입니다 . 인터페이스에는 구현 세부 정보가 없으므로 코드가 느슨하게 연결됩니다.

구현 세부 사항은 시간이 지남에 따라 변경 될 수 있지만 상호 작용하는 모든 것이 구현이 아닌 인터페이스와 관련되므로 나머지 코드에는 영향을 미치지 않습니다. 구현이 어떤지 신경 쓰지 않아도됩니다 ... 알고있는 것은 인터페이스를 구현하는 클래스가 있다는 것입니다.


3

따라서이 권리를 얻으려면 인터페이스의 장점은 특정 클래스와 메소드 호출을 분리 할 수 ​​있다는 것입니다. 대신 인터페이스의 인스턴스를 작성하십시오. 여기서 인터페이스를 구현하는 클래스를 선택하십시오. 따라서 비슷하지만 약간 다른 기능을 가진 많은 클래스를 가질 수 있으며 어떤 경우에는 (인터페이스의 의도와 관련된 경우) 어떤 객체인지 신경 쓰지 않습니다.

예를 들어, 운동 인터페이스를 가질 수 있습니다. 무언가 '움직임'과 움직임 인터페이스를 구현하는 객체 (사람, 자동차, 고양이)를 만드는 방법이 전달되어 움직일 수 있습니다. 방법이 없으면 클래스의 유형을 모두 알 수 있습니다.


3

플러그인으로 확장 할 수있는 'Zebra'라는 제품이 있다고 상상해보십시오. 일부 디렉토리에서 DLL을 검색하여 플러그인을 찾습니다. 모든 DLL을로드하고 리플렉션을 사용하여 구현하는 클래스를 찾은 IZebraPlugin다음 해당 인터페이스의 메소드를 호출하여 플러그인과 통신합니다.

이것은 특정 플러그인 클래스와 완전히 독립적입니다. 클래스가 무엇이든 상관하지 않습니다. 인터페이스 사양을 충족시키는 것만 걱정합니다.

인터페이스는 이와 같은 확장 성 지점을 정의하는 방법입니다. 인터페이스와 통신하는 코드는 더 느슨하게 연결됩니다. 실제로 다른 특정 코드에는 전혀 연결되지 않습니다. 원래 개발자를 만난 적이없는 사람들이 몇 년 후 작성한 플러그인과 상호 운용 할 수 있습니다.

대신 가상 함수와 함께 기본 클래스를 사용할 수 있습니다. 모든 플러그인은 기본 클래스에서 파생됩니다. 그러나 클래스는 하나의 기본 클래스 만 가질 수있는 반면 제한없이 인터페이스를 구현할 수 있으므로 훨씬 제한적입니다.


3

C ++ 설명.

인터페이스를 클래스 공용 메소드로 생각하십시오.

그런 다음 자신의 기능을 수행하기 위해 이러한 공용 메소드에 '종속적 인'템플리트를 작성할 수 있습니다 (클래스 공용 인터페이스에 정의 된 함수 호출을 작성 함). 이 템플릿이 Vector 클래스와 같은 컨테이너이고이 템플릿이 의존하는 인터페이스가 검색 알고리즘이라고 가정하겠습니다.

함수 / 인터페이스 Vector가 호출하는 것을 정의하는 모든 알고리즘 클래스는 '원본 답장에 설명 된대로' '계약'을 충족시킵니다. 알고리즘은 동일한 기본 클래스 일 필요도 없습니다. 유일한 요구 사항은 Vector가 의존하는 함수 / 방법 (인터페이스)이 알고리즘에 정의되어 있어야한다는 것입니다.

이 모든 점은 Vector가 의존하는 인터페이스 (버블 검색, 순차적 검색, 빠른 검색)를 제공하는 한 다른 검색 알고리즘 / 클래스를 제공 할 수 있다는 것입니다.

검색 알고리즘이 의존하는 인터페이스 / 계약을 수행하도록하여 벡터와 동일한 검색 알고리즘을 활용하는 다른 컨테이너 (목록, 대기열)를 디자인 할 수도 있습니다.

자란 상속 트리로 문제를 지나치게 복잡하게 만들지 않고 생성하는 모든 새 객체에 대해 알고리즘을 반복해서 작성할 수 있기 때문에 시간 (OOP 원칙 '코드 재사용')이 절약됩니다.

일이 어떻게 작동하는지에 대한 '누락'에 관해서는; 표준 TEMPLATE 라이브러리의 프레임 워크가 대부분 작동하는 방식이므로 (최소한 C ++에서는) 큰 시간이 걸립니다.

물론 상속과 추상 클래스를 사용할 때 인터페이스에 대한 프로그래밍 방법이 변경됩니다. 그러나 원칙은 동일합니다. 공용 함수 / 메소드는 클래스 인터페이스입니다.

이것은 큰 주제이며 디자인 패턴의 초석 원칙 중 하나입니다.


3

Java에서 이러한 구체적인 클래스는 모두 CharSequence 인터페이스를 구현합니다.

CharBuffer, 문자열, StringBuffer, StringBuilder

이 구체적인 클래스에는 Object 이외의 공통 상위 클래스가 없으므로 각 문자 배열과 관련이 있거나이를 나타내는 또는 조작하는 것과는 관련이 없습니다. 예를 들어, String 객체는 인스턴스화되면 String의 문자를 변경할 수 없지만 StringBuffer 또는 StringBuilder의 문자는 편집 할 수 있습니다.

그러나이 클래스들 각각은 CharSequence 인터페이스 메소드를 적절하게 구현할 수 있습니다 :

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

경우에 따라 String을 허용하는 데 사용 된 Java 클래스 라이브러리 클래스가 이제 CharSequence 인터페이스를 허용하도록 개정되었습니다. 따라서 StringBuilder 인스턴스가있는 경우 String 객체를 추출하는 대신 (새 객체 인스턴스를 인스턴스화하는 것을 의미 함) 대신 CharSequence 인터페이스를 구현할 때 StringBuilder 자체를 전달할 수 있습니다.

일부 클래스가 구현하는 Appendable 인터페이스는 기본 콘크리트 클래스 객체 인스턴스의 인스턴스에 문자를 추가 할 수있는 모든 상황에서 거의 동일한 종류의 이점을 제공합니다. 이러한 모든 구체적인 클래스는 Appendable 인터페이스를 구현합니다.

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer


너무 나쁜 인터페이스입니다 CharSequence빈혈 . Java와 .NET이 인터페이스가 기본 구현을 허용하여 사람들이 상용구 코드를 최소화하기 위해 인터페이스를 완전히 분석하지 않기를 바랍니다. 합법적 인 CharSequence구현이 주어지면 String위의 4 가지 방법 만 사용 하는 대부분의 기능을 에뮬레이션 할 수 있지만 많은 구현은 다른 방식으로 훨씬 효율적으로 이러한 기능을 수행 할 수 있습니다. 불행히도, 특정 구현이 CharSequence모든 것을 단일 로 보유하고 char[]많은 것을 수행 할 수있다
하더라도

... indexOf빠른 작동과 같이 특정 구현에 익숙하지 않은 호출자가 개별 문자를 검사 CharSequence하는 데 사용 charAt하는 대신 요청 을 할 수 있는 방법은 없습니다 .
supercat '10

3

짧은 이야기 : 우체부는 집으로 돌아와서 전달할 주소가 적힌 표지 (문자, 서류, 수표, 기프트 카드, 신청서, 연애 편지)를받습니다.

표지가없고 우체국에 집으로 돌아와서 모든 물건을 받고 다른 사람들에게 배달하도록 요청한다고 가정하면 우체국은 혼란 스러울 수 있습니다.

그래서 커버로 감싸는 것이 좋습니다 (우리의 이야기에서는 인터페이스입니다). 그는 그의 일을 잘 할 것입니다.

우체부의 임무는 단지 표지 만 받고 전달하는 것입니다 (그는 표지 안에있는 것을 귀찮게하지 않을 것입니다).

interface실제 유형이 아닌 유형을 작성 하지만 실제 유형으로 구현하십시오.

인터페이스를 만들려면 구성 요소가 나머지 코드에 쉽게 맞습니다.

예를 들어 보겠습니다.

아래와 같이 AirPlane 인터페이스가 있습니다.

interface Airplane{
    parkPlane();
    servicePlane();
}

Controller 클래스의 Plane에 메소드가 있다고 가정하십시오.

parkPlane(Airplane plane)

servicePlane(Airplane plane)

프로그램에서 구현됩니다. 코드가 중단 되지 않습니다 . 의미하는대로 인수를 허용하는 한 변경할 필요가 없습니다 AirPlane.

그것은 실제의 형태에도 불구하고 어떤 비행기를 받아 들일 것입니다 때문에, flyer, highflyr, fighter, 등

또한 컬렉션에서 :

List<Airplane> plane; // 모든 비행기를 가져갑니다.

다음 예는 이해를 명확하게합니다.


당신은 그것을 구현하는 전투기가 있습니다.

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

HighFlyer 및 기타 clasess에 대해서도 동일합니다.

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

이제 컨트롤러 클래스를 사용하여 AirPlane 여러 번 .

Controller 클래스가 아래와 같이 ControlPlane이라고 가정합니다.

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

당신이 새로운 것을 만들 때 여기 마법이 온다 AirPlane 유형의 인스턴스를 원하는만큼 만들 수 있으며 ControlPlane클래스 코드를 변경하지 않는 .

인스턴스를 추가 할 수 있습니다 ...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

이전에 생성 된 유형의 인스턴스도 제거 할 수 있습니다.


2

인터페이스는 계약과 유사하며, 구현 클래스가 계약 (인터페이스)으로 작성된 메소드를 구현하도록합니다. Java는 다중 상속을 제공하지 않으므로 "인터페이스 프로그래밍"은 다중 상속을 달성하는 좋은 방법입니다.

클래스 A가 이미 다른 클래스 B를 확장하고 있지만 해당 클래스 A가 특정 지침을 따르거나 특정 계약을 구현하려는 경우 "프로그래밍 인터페이스"전략을 통해이를 수행 할 수 있습니다.


2

Q :-... "인터페이스를 구현하는 클래스를 사용할 수 있습니까?"
A :-그렇습니다.

Q :-... "언제 언제해야합니까?"
A :-인터페이스를 구현하는 클래스가 필요할 때마다.

참고 : 우리는 클래스에 의해 구현이 아닌 인터페이스를 인스턴스화 할 수있는 - 사실을.

  • 왜?
  • 인터페이스에는 정의가 아닌 메소드 프로토 타입 만 있으므로 (논리가 아닌 함수 이름 만)

AnIntf anInst = new Aclass();
// Aclass가 AnIntf를 구현 한 경우에만 이를 수행 할 수 있습니다.
// anInst에는 Aclass 참조가 있습니다.


참고 : 이제 Bclass와 Cclass가 동일한 Dintf를 구현 한 경우 무슨 일이 있었는지 이해할 수있었습니다.

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

우리가 가진 것 : 동일한 인터페이스 프로토 타입 (인터페이스의 함수 이름)과 다른 구현을 호출합니다.

참고 문헌 : 프로토 타입-Wikipedia


1

인터페이스에 대한 프로그램을 통해 인터페이스에 의해 정의 된 계약의 구현을 완벽하게 변경할 수 있습니다. 계약과 특정 구현 사이의 느슨한 결합을 허용합니다.

IInterface classRef = new ObjectWhatever()

IInterface를 구현하는 클래스를 사용할 수 있습니까? 언제해야합니까?

이 SE 질문에서 좋은 예를 살펴보십시오.

Java 클래스의 인터페이스가 선호되는 이유는 무엇입니까?

인터페이스를 사용하면 성능이 저하됩니까?

그렇다면 얼마나?

예. 몇 초 안에 약간의 성능 오버 헤드가 발생합니다. 그러나 애플리케이션에 인터페이스 구현을 동적으로 변경해야하는 경우 성능 영향에 대해 걱정하지 마십시오.

두 비트의 코드를 유지하지 않고도 어떻게 피할 수 있습니까?

응용 프로그램에 필요한 경우 여러 인터페이스 구현을 피하려고 시도하지 마십시오. 하나의 특정 구현과 인터페이스가 밀접하게 연결되어 있지 않은 경우 한 구현을 다른 구현으로 변경하기 위해 패치를 배포해야 할 수도 있습니다.

하나의 좋은 사용 사례 : 전략 패턴의 구현 :

전략 패턴의 실제 예


1

인터페이스 프로그램은 GOF 책의 용어입니다. 직접 Java 인터페이스와 관련이 있지만 실제 인터페이스와 관련이 있다고 직접 말하지는 않습니다. 깨끗한 계층 분리를 달성하려면 시스템간에 약간의 분리를 만들어야합니다. 예를 들어 사용하려는 구체적인 데이터베이스가 있다고 가정하고 "데이터베이스에 프로그래밍"하지 않고 "스토리지 인터페이스에 프로그래밍"한다고 가정 해 보겠습니다. 마찬가지로 "웹 서비스로 프로그래밍"하는 대신 "클라이언트 인터페이스"로 프로그래밍합니다. 이것은 쉽게 물건을 교환 할 수 있도록합니다.

이 규칙이 도움이된다고 생각합니다.

1 . 여러 유형의 객체가있는 경우 Java 인터페이스를 사용합니다. 단일 객체 만 있으면 요점을 알 수 없습니다. 적어도 두 가지 구체적인 아이디어 구현이 있다면 Java 인터페이스를 사용합니다.

2 . 위에서 언급했듯이 외부 시스템 (스토리지 시스템)에서 자체 시스템 (로컬 DB)으로 디커플링을 가져 오려면 인터페이스를 사용하십시오.

사용시기를 고려해야하는 두 가지 방법이 있습니다. 도움이 되었기를 바랍니다.


0

또한 여기에 좋은 설명이 많이 있습니다.이 방법을 사용할 때 알아 낸 추가 정보를 포함하여 여기에 내 관점을 제시하고 싶습니다.

단위 테스트

지난 2 년 동안 저는 취미 프로젝트를 작성했으며 이에 대한 단위 테스트는 작성하지 않았습니다. 약 50K 줄을 쓴 후에 단위 테스트를 작성하는 것이 실제로 필요하다는 것을 알았습니다. 나는 인터페이스를 사용하지 않았으며 (또는 매우 드물게) ... 첫 번째 단위 테스트를 할 때 인터페이스가 복잡하다는 것을 알았습니다. 왜?

많은 클래스 인스턴스를 만들어야했기 때문에 클래스 변수 및 / 또는 매개 변수로 입력하는 데 사용되었습니다. 따라서 테스트는 통합 테스트와 비슷해 보입니다 (모두 묶여 있기 때문에 클래스의 완전한 '프레임 워크'를 만드는 것).

인터페이스에 대한 두려움 그래서 인터페이스 를 사용하기로 결정했습니다. 내 두려움은 모든 기능을 모든 곳에서 (사용 된 모든 클래스에서) 여러 번 구현해야한다는 것이 었습니다. 어떤면에서는 이것이 사실이지만 상속을 사용하면 많이 줄일 수 있습니다.

인터페이스와 상속 의 조합 나는 조합이 사용하기에 매우 좋다는 것을 알았습니다. 나는 매우 간단한 예를 제시합니다.

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

이러한 방식으로 코드를 복사 할 필요는 없지만 자동차를 인터페이스 (ICar)로 사용하는 이점이 있습니다.


0

먼저 몇 가지 정의부터 시작하겠습니다.

인터페이스 n. 객체의 조작에 의해 정의 된 모든 서명 세트를 객체에 대한 인터페이스라고합니다.

n을 입력 하십시오. 특정 인터페이스

의 간단한 예 인터페이스는 상기 정의 된 바와 같은 모든 PDO 객체 메소드 것 query(), commit(), close()전체가 아닌 별도 등. 이러한 메소드, 즉 해당 인터페이스는 전체 메시지 세트, 오브젝트로 보낼 수있는 요청을 정의합니다.

유형 상기 정의 된 바와 같은 특정 인터페이스이다. 내가 보여주기 위해 만들어 낸 모양의 인터페이스를 사용합니다 : draw(), getArea(), getPerimeter()

객체가 데이터베이스 유형의 경우 우리가 메시지 / 데이터베이스 인터페이스의 요청을 수락한다는 것을 의미, query(), commit()등 오브젝트는 여러 유형이 될 수 있습니다. 데이터베이스 객체가 인터페이스를 구현하는 한 형태 유형을 가질 수 있습니다.이 경우 하위 유형이됩니다 .

많은 객체가 다양한 인터페이스 / 유형이 될 수 있으며 해당 인터페이스를 다르게 구현할 수 있습니다. 이를 통해 객체를 대체하여 사용할 객체를 선택할 수 있습니다. 다형성이라고도합니다.

클라이언트는 인터페이스 만 인식하고 구현은 인식하지 못합니다.

그래서 인터페이스에 에센스 프로그래밍과 같은 추상 클래스의 몇 가지 유형을 포함 할 Shape경우에만 즉, 지정된 인터페이스에 draw(), getCoordinates(), getArea()등 그리고 다른 구체적인 클래스는 이러한 Circle 클래스, 광장 클래스, 삼각형 클래스로 그 인터페이스를 구현해야합니다. 따라서 구현이 아닌 인터페이스로 프로그램하십시오.


0

"인터페이스 프로그램"은 하드 코드를 올바르게 제공하지 않음을 의미합니다. 즉, 이전 기능을 중단하지 않고 코드를 확장해야합니다. 이전 코드를 편집하지 않고 확장 만 가능합니다.

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