[oop] 언제 추상 클래스 대신 인터페이스를 사용해야합니까?

이것은 일반적인 OOP 질문 일 수 있습니다. 사용법을 기준으로 인터페이스와 추상 클래스 사이의 일반적인 비교를 원했습니다.

언제 인터페이스를 사용하고 싶고 언제 추상 클래스를 사용하고 싶 습니까?



답변

나는 그것에 관한 기사를 썼다 :

추상 클래스와 인터페이스

요약 :

추상 클래스에 대해 이야기 할 때 객체 유형의 특성을 정의합니다. 객체가 무엇인지 지정 .

인터페이스에 대해 이야기하고 제공하기로 약속 한 기능을 정의 할 때 객체가 수행 할 수있는 작업에 대한 계약을 설정하는 것에 대해 이야기하고 있습니다.


답변

추상 클래스는 공유 상태 또는 기능을 가질 수 있습니다. 인터페이스는 상태 또는 기능을 제공한다는 약속 일뿐입니다. 좋은 추상 클래스는 기능이나 상태를 공유 할 수 있기 때문에 다시 작성해야하는 코드의 양을 줄입니다. 인터페이스에 공유 할 정의 된 정보가 없습니다


답변

개인적으로 저는 추상 클래스를 작성할 필요가 거의 없습니다.

대부분 추상 클래스가 잘못 사용되는 것을 본 것은 추상 클래스 작성자가 “템플릿 메소드”패턴을 사용하기 때문입니다.

“템플릿 메소드”의 문제점은 거의 항상 재진입한다는 점입니다. “파생”클래스는 구현하는 기본 클래스의 “추상”메소드뿐만 아니라 기본 클래스의 공용 메소드에 대해서도 알고 있습니다. 대부분의 경우 전화를 걸 필요는 없습니다.

(과도하게 단순화 된) 예 :

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

따라서이 클래스의 저자는 일반적인 알고리즘을 작성했으며 사람들이 자신의 “후크”(이 경우에는 “비교”) 방법을 제공하여 “전문화”하여 알고리즘을 사용하려고합니다.

따라서 의도 된 사용법은 다음과 같습니다.

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

이것의 문제점은 두 개념을 과도하게 결합했다는 것입니다.

  1. 두 항목을 비교하는 방법 (먼저 어떤 항목을 수행해야하는지)
  2. 항목을 정렬하는 방법 (즉, 빠른 정렬 대 병합 정렬 등)

위의 코드에서 이론적으로 “비교”방법의 작성자는 재진입 할 수 있습니다. 작업을 원하지 않거나 수행하지 않아도 수퍼 클래스 “Sort”메소드를 .

이 불필요한 커플 링에 대한 비용은 수퍼 클래스를 변경하기 어렵고 대부분의 OO 언어에서는 런타임에 변경할 수 없다는 것입니다.

다른 방법은 “전략”디자인 패턴을 대신 사용하는 것입니다.

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

지금 우리가 가지고있는 것은 인터페이스와 인터페이스의 구체적인 구현입니다. 실제로 높은 수준의 OO 디자인을 수행하기 위해 실제로 다른 작업이 필요하지 않습니다.

“QuickSort”클래스와 “NameComparator”를 사용하여 “이름 분류”를 구현했다는 사실을 “숨기기”위해 여전히 팩토리 메소드를 작성할 수 있습니다.

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

모든 기본 및 파생 클래스 사이에 자연 재진입 관계가 심지어 당신은 당신이 할 수있는 추상 클래스가 시간이 …, 그것은 일반적으로 그들에게 명시 적으로 만들기 위해 지불한다.

마지막 생각 : 위에서 우리가 한 것은 “QuickSort”함수와 “NameComparison”함수를 사용하여 “NameSorting”함수를 “구성”하는 것입니다. 적은 코드로.


답변

Java를 OOP 언어로보고 있다면

인터페이스는 메소드 구현을 제공하지 않습니다 “는 더 이상 Java 8 실행에서 유효하지 않습니다. 이제 java는 기본 메소드의 인터페이스에서 구현을 제공합니다.

간단히 말해서 사용하고 싶습니다

인터페이스 : 여러 관련되지 않은 객체로 계약을 구현합니다. “ HAS A “기능을 제공합니다.

추상 클래스 : 여러 관련 개체간에 동일하거나 다른 동작을 구현합니다. “ IS A “관계를 설정합니다.

Oracle 웹 사이트 는 클래스 interfaceabstract클래스의 주요 차이점을 제공합니다 .

다음과 같은 경우 추상 클래스 사용을 고려하십시오 .

  1. 밀접하게 관련된 여러 클래스간에 코드를 공유하려고합니다.
  2. 추상 클래스를 확장하는 클래스에는 많은 공통 메소드 또는 필드가 있거나 public 이외의 액세스 수정 자 (예 : 보호 및 개인)가 필요합니다.
  3. 비 정적 또는 최종이 아닌 필드를 선언하려고합니다.

다음과 같은 경우 인터페이스 사용을 고려하십시오 .

  1. 관련없는 클래스가 인터페이스를 구현할 것으로 기대합니다. 예를 들어, 많은 관련이없는 객체가 Serializable인터페이스 를 구현할 수 있습니다.
  2. 특정 데이터 유형의 동작을 지정하려고하지만 누가 해당 동작을 구현하는지는 신경 쓰지 않습니다.
  3. 여러 유형의 상속을 활용하려고합니다.

예:

추상 클래스 ( IS A 관계)

리더 는 추상 클래스입니다.

BufferedReaderReader

FileReaderReader

FileReader그리고 BufferedReader공통의 목적으로 사용됩니다 : 데이터 읽기, 그리고 Reader수업을 통해 관련됩니다 .

인터페이스 ( HAS A 기능)

직렬화 는 인터페이스입니다.

애플리케이션에 Serializable인터페이스를 구현하는 두 개의 클래스가 있다고 가정하십시오.

Employee implements Serializable

Game implements Serializable

여기서 와의 Serializable인터페이스를 통해 관계를 설정할 수는 없습니다 . 이는 다른 목적을위한 것입니다. 둘 다 상태를 직렬화 할 수 있으며 비교는 거기서 끝납니다.EmployeeGame

이 게시물을 살펴보십시오.

Interface와 Abstract 클래스의 차이점을 어떻게 설명해야합니까?


답변

좋아, 방금이 “그 자체”를 가지고-여기 평신도의 용어에 있습니다 (내가 틀렸다면 저를 바로 잡으십시오)-나는이 주제가 거무스름하다는 것을 알고 있지만 다른 누군가가 그것을 우연히 발견 할 수 있습니다 …

추상 클래스를 사용하면 블루 프린트를 만들 수 있으며 모든 자손이 소유 할 속성 및 메서드를 추가로 구성 (구현) 할 수 있습니다.

반면에 인터페이스를 사용하면 지정된 이름의 속성 및 / 또는 메서드를 구현하는 모든 클래스에 존재한다고 선언 할 수 있지만 구현 방법을 지정하지는 않습니다. 또한 클래스는 많은 인터페이스를 구현할 수 있지만 ONE Abstract 클래스 만 확장 할 수 있습니다. 인터페이스는 고급 아키텍처 도구에 가깝습니다 (디자인 패턴을 파악하기 시작하면 더 명확 해짐). 초록은 두 캠프 모두에 발을 들여 놓았으며 더러운 작업도 수행 할 수 있습니다.

왜 다른 것을 사용합니까? 전자는 후손 에 대한보다 구체적인 정의를 허용합니다. 후자는 더 큰 다형성을 허용합니다 . 이 마지막 요점은 최종 사용자 / 코더에게 중요하며,이 정보를 사용 하여 필요에 맞게 다양한 조합 / 모양으로 AP I (nterface) 을 구현할 수 있습니다 .

필자는 이것이 “전구”의 순간이라고 생각한다. 인터페이스는 프로젝트의 구현을 추가하거나 API를 확장 하는 체인에서 나중에 나오는 코더의 인터페이스와 더 가깝다 .


답변

내 두 센트 :

인터페이스는 기본적으로 모든 구현 클래스가 준수해야하는 계약을 정의합니다 (인터페이스 멤버 구현). 코드가 포함되어 있지 않습니다.

반면에 추상 클래스에는 코드가 포함될 수 있으며 상속 클래스가 구현해야하는 abstract로 표시된 일부 메소드가있을 수 있습니다.

내가 추상 클래스를 사용한 드문 상황은 상속 클래스가 추상 기본 클래스와 같이 일부 특수 클래스가 상속하는 재정의에 흥미가 없을 수있는 기본 기능이있을 때입니다.

예 (아주 초보적인 하나!)와 같은 추상 메서드가 기본 클래스라는 고객을 고려 CalculatePayment(), CalculateRewardPoints()과 같은 몇 가지 않는 추상적 인 방법을 GetName(), SavePaymentDetails().

같은 수업을 전문 RegularCustomerGoldCustomer로부터 상속 Customer기본 클래스 자신의 구현 CalculatePayment()CalculateRewardPoints()방법 논리를하지만, 재사용 GetName()SavePaymentDetails()방법을.

이전 버전을 사용하는 하위 클래스에 영향을주지 않고 추상 클래스 (비 추상 메소드)에 더 많은 기능을 추가 할 수 있습니다. 인터페이스에 메소드를 추가하면 새로 추가 된 인터페이스 멤버를 구현해야하므로 인터페이스를 구현하는 모든 클래스에 영향을 미칩니다.

모든 추상 멤버를 가진 추상 클래스는 인터페이스와 유사합니다.


답변

개념이 마음에 명확하다면, 아주 간단한 일을해야 할 때.

인터페이스는 구현할 수 있지만 추상 클래스는 파생 될 수 있습니다. 둘 사이에는 약간의 차이가 있습니다. Abstract 클래스를 파생시킬 때 파생 클래스와 기본 클래스 간의 관계는 ‘is a’관계입니다. 예를 들어, Dog는 Animal, Sheep은 Animal입니다. 이는 파생 클래스가 기본 클래스의 일부 속성을 상속 함을 의미합니다.

인터페이스 구현의 경우 관계는 “할 수 있습니다”. 예를 들어, 개는 스파이 개일 수 있습니다. 개는 서커스 개가 될 수 있습니다. 개는 경주 개가 될 수 있습니다. 이는 무언가를 얻기 위해 특정 방법을 구현한다는 것을 의미합니다.

나는 분명하기를 바랍니다.