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


427

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

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


1
이것은 많은 질문을 받았습니다 : stackoverflow.com/questions/56867/interface-vs-base-class
mmcdole

1
아래의 답변 외에도 인터페이스를 선호하는 위치와 원하지 않는 위치에 대한 간단한 짧은 목록이 있습니다. 인터페이스 사용시기 : msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
Anthony

수업이 어떻게 될지 확신 할 수 없을 때는 초록을 사용하십시오. 있다면 인터페이스를 사용하십시오.
Uğur Gümüşhan

Microsoft에서 일하지 않는 개발자가 일상 개발에서 인터페이스를 정의하고 사용하는 개발자가 몇 명인지 알고 싶습니다.
user1451111

답변:


431

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

추상 클래스와 인터페이스

요약 :

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

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


114
이것은 매우 도움이되었습니다 : Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk". 감사합니다
07 초

2
연결이 끊어진 것 같습니다.
Kim Ahlstrøm Meyn Mathiassen

Alex의 설명은 다음과 같습니다. 구현 된 기능 만 설명하고 저장된 상태를 설명하는 것의 차이점은이 질문에 대한 더 나은 대답 인 것 같습니다. 차이점은 단지 철학적이지 않기 때문입니다.
Duncan Malashock

1
던컨 Malashock, 실제로는 아닙니다. 호르헤의 대답이 더 좋습니다. Alex의 대답은 역학에 중점을두고 Jorge는 의미에 중점을 둡니다.
Nazar Merza

8
나는 당신의 지정된 답변 앞에 진술을 좋아합니다 :Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
S1r-Lanzelot

433

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


65
이것은 나에게 가장 좋은 대답이며, 더 높은 표를 얻지 않은 것은 부끄러운 일입니다. 그렇습니다. 두 개념 사이에는 철학적 인 차이점이 있지만 근본 요점은 추상 클래스가 모든 하위 항목이 기능 / 상태를 공유하고 인터페이스가 공통된 결합 만 보장한다는 점입니다.
drharris

3
예를 들어, 템플리트 메소드 디자인 패턴 에는 추상 기본 클래스가 사용 되지만 전략 디자인 패턴 에는 인터페이스가 사용됩니다 .
Raedwald

1
나는 Jorge의 요약이 두 가지 모두의 존재 뒤에 있지만 기본은 Alex의 답변이 결과의 차이라고 설명합니다. 나는 둘 다 정답으로 표시 할 수 있기를 희망하지만 여전히 호르헤의 대답을 선호합니다.
Chirantan

그리고 여기 코드 가있는 예제 가 있습니다.
shaijut

저에게 "좋은 추상 클래스는 기능이나 상태를 공유 할 수 있기 때문에 다시 작성해야하는 코드의 양을 줄입니다." 진술은 답의 핵심입니다.
Div Tiwari

82

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

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

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

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

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"함수를 "구성"하는 것입니다. 적은 코드로.


5
Abstract 클래스 나 템플릿 메소드 패턴을 사용할 수 있다고해서 반드시 피해야하는 것은 아닙니다. 전략 패턴은이 예와 다른 상황에서 다른 패턴이지만 템플릿 패턴이 전략보다 훨씬 더 적합한 예가 많이 있습니다.
Jorge Córdoba

5
글쎄, 내 경험상 나는 결코 템플릿 템플릿이 선호되는 상황에 빠지지 않는다. 그리고 이것이 "추상"입니다. "템플릿 방법"디자인 패턴에 대한 언어 지원입니다.
Paul Hollingsworth

좋아, 프로세스가 비슷한 전문가 시스템에 한 번 사용했습니다. 1. FillTheParameters, 2. Vector Products를 그들 사이에 만드십시오. 기본 클래스에서 위임되고 2 및 4가 구현됩니다.
Jorge Córdoba

10
나는 거의 모든 추상 클래스 사용을 이해하기가 더 어렵다는 것을 안다. 대신 상속 관계의 서로 통신 상자의 측면에서 생각하는 것은 (나를 위해) 더 쉽습니다 ... 그러나 나는 또한 현재 OO 언어가 너무 상용구를 강제로 동의 ... 기능 OO를 통해 갈 수있는 방법이 될 것입니다
폴 홀 링스 워스

4
오용의 예는 매우 사소합니다. 비교와 같은 훌륭한 제거 기능으로 거의 귀결되지 않습니다. 파생 클래스가 대체 하거나 확장 하는 기본 기능이있는 상황이 더 일반적입니다 (후자의 경우 기본 클래스 함수를 호출하는 것이 완벽하게 유효 함). 귀하의 예에는 기본 기능이 없으므로 추상 클래스의 사용에는 정당성이 없습니다.
SomeWittyUsername

41

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 클래스의 차이점을 어떻게 설명해야합니까?


40

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

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

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

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

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


이것을 기반으로 : 인터페이스를 구현하는 객체가 TYPE을 취합니다. 이것은 중요합니다. 따라서 인터페이스의 다양한 변형을 클래스에 전달할 수 있지만 인터페이스의 유형 이름이있는 인터페이스 (및 해당 메소드)를 참조하십시오. 따라서 스위치 나 if / else 루프가 필요 없습니다. 주제에 대해이 학습서를 시도하십시오-전략 패턴을 통한 인터페이스 사용을 보여줍니다. phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung

나는 당신의 전구 순간에 대해 전적으로 동의합니다 : "다양한 조합 / 모양의 API (nterface)가 그들의 요구에 맞습니다"! 아주 좋은 지적입니다.
Trevor Boyd Smith

39

내 두 센트 :

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

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

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

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

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

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

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


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

인터페이스는 "기본"메소드를 가질 수 있으므로 인터페이스에 메소드 impl이없는 것은 잘못된 생각입니다. "부모-자녀"IS-A 관계가 핵심입니다. 또한 "공유 속성"과 "공유 속성". 예를 들어 개 iS-A 동물. 그러나 개는 또한 "걸어"수
ha9u63ar

30

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

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

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

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


11

1. 관련없는 클래스에 공통적 인 기능을 제공하는 인터페이스를 만드는 경우 인터페이스를 사용하십시오.

2. 계층 구조와 밀접하게 관련된 객체를 위해 무언가를 생성하는 경우 추상 클래스를 사용하십시오.



7

나는 그것을 간결하게 만드는 가장 간결한 방법은 다음과 같다고 생각한다.

공유 속성 => 추상 클래스.
공유 기능 => 인터페이스.

간결하게 말하면 ...

추상 클래스 예 :

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

동물은 공유 된 속성 (이 경우 다리 수)을 가지기 때문에이 공유 된 속성을 포함하는 추상 클래스를 만드는 것이 좋습니다. 또한 해당 속성에서 작동하는 공통 코드를 작성할 수 있습니다. 예를 들면 다음과 같습니다.

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

인터페이스 예 :

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Vuvuzelas와 Cars는 완전히 다른 것이지만 소리를 만드는 기능을 공유합니다. 따라서 인터페이스는 여기서 의미가 있습니다. 또한 프로그래머는 공통 인터페이스 ( IMakeSound이 경우)에서 소리를 만드는 것을 그룹화 할 수 있습니다. 이 디자인으로 다음 코드를 작성할 수 있습니다.

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

그것이 무엇을 출력 할 것인지 말할 수 있습니까?

마지막으로 두 가지를 결합 할 수 있습니다.

결합 된 예 :

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

여기서 우리는 모두 BaseAnimal소리를 내야하지만 아직 그 구현을 모릅니다. 이 경우 인터페이스 구현을 추상화하고 해당 구현을 서브 클래스에 위임 할 수 있습니다.

마지막으로, 추상 클래스 예제에서 다른 객체의 공유 속성을 어떻게 조작 할 수 있었는지, 인터페이스 예제에서 다른 객체의 공유 기능을 호출 할 수 있었던 방법을 기억하십니까? 이 마지막 예에서 우리는 둘 다 할 수 있습니다.


7

인터페이스보다 추상 클래스를 선호하는 경우

  1. 프로그램 / 프로젝트 기간 동안 기본 클래스를 업데이트 할 계획이면 기본 클래스를 추상 클래스로 만드는 것이 가장 좋습니다.
  2. 계층 구조와 밀접한 관련이있는 개체에 대한 백본을 작성하려는 경우 추상 클래스를 사용하는 것이 좋습니다.

언제 추상 클래스보다 인터페이스를 선호합니까?

  1. 대규모 계층 구조의 프레임 워크를 다루지 않는 경우 인터페이스를 선택하는 것이 좋습니다.
  2. 추상 클래스 (다이아몬드 문제)에서는 다중 상속이 지원되지 않으므로 인터페이스가 하루를 절약 할 수 있습니다.

거의 10 년 전의 질문에 22 번째 답이 필요하다고 생각한 이유는 무엇입니까?
jonrsharpe 23시 08 분

3
같은 유형의 사고로 질문에 대한 간단한 답변을 찾게되었습니다.
Satya

1
FWIW, 나는이 답변을 정말 좋아합니다.
브렌트 리튼 하우스 19

6

클래스는 하나의 기본 클래스에서만 상속 될 수 있으므로 추상 클래스를 사용하여 클래스 그룹에 다형성을 제공하려면 해당 클래스에서 모두 상속해야합니다. 추상 클래스는 이미 구현 된 멤버를 제공 할 수도 있습니다. 따라서 추상 클래스에서는 일정량의 동일한 기능을 보장 할 수 있지만 인터페이스로는 불가능합니다.

다음은 구성 요소에 다형성을 제공하기 위해 인터페이스 또는 추상 클래스를 사용할지 여부를 결정하는 데 도움이되는 몇 가지 권장 사항입니다.

  • 컴포넌트의 여러 버전을 작성할 것으로 예상되는 경우 추상 클래스를 작성하십시오. 추상 클래스는 구성 요소를 간단하고 쉽게 버전화할 수있는 방법을 제공합니다. 기본 클래스를 업데이트하면 모든 상속 클래스가 자동으로 변경됩니다. 반면에 인터페이스는 그런 식으로 만든 후에는 변경할 수 없습니다. 새로운 버전의 인터페이스가 필요한 경우 완전히 새로운 인터페이스를 만들어야합니다.
  • 작성중인 기능이 광범위한 다른 객체에 유용 할 경우 인터페이스를 사용하십시오. 추상 클래스는 주로 밀접한 관련이있는 객체에 사용해야하지만 인터페이스는 관련없는 클래스에 공통 기능을 제공하는 데 가장 적합합니다.
  • 작고 간결한 기능의 비트를 디자인하는 경우 인터페이스를 사용하십시오. 큰 기능 단위를 디자인하는 경우 추상 클래스를 사용하십시오.
  • 구성 요소의 모든 구현에서 공통의 구현 기능을 제공하려면 추상 클래스를 사용하십시오. 추상 클래스를 사용하면 클래스를 부분적으로 구현할 수 있지만 인터페이스에는 멤버에 대한 구현이 없습니다.

http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx 에서 복사


UML에는 다중 클래스 상속을 배제하는 것이 없습니다. 다중 상속은 UML이 아닌 프로그래밍 언어에 의해 결정됩니다. 예를 들어, Java 및 C #에서는 다중 클래스 상속이 허용되지 않지만 C ++에서는 다중 클래스 상속이 허용됩니다.
BobRodes

@BobRodes : 객체 지향 프레임 워크가 다양한 조합으로 제공 할 수있는 기능은 많지만 모든 조합이 아닙니다. 일반화 된 다중 상속은 실제 인스턴스의 상위 유형 또는 지원되는 인터페이스 유형으로 직접 참조를 캐스트하는 기능과 기본 유형 및 파생 된 유형을 독립적으로 컴파일하여 런타임에 결합하는 기능을 포함하여 다른 유용한 기능 조합을 배제합니다.
supercat

@supercat Yours는 다중 상속을 사용하여 발생하는 일부 문제에 대한 좋은 설명입니다. 그럼에도 불구하고 UML에는 다이어그램에서 다중 클래스 상속을 방해하는 것이 없습니다. 나는 위의 "클래스는 하나의 기본 클래스에서만 상속받을 수 있습니다 ..."라고 대답했습니다.
BobRodes

@BobRodes : 질문은 Java로 태그되었습니다. Java에는 표시된 기능이 포함되어 있으므로 "치명적인 다이아몬드"를 생성 할 수없는 다중 상속 형태로 제한됩니다 (사실 기본 인터페이스 구현을 구현 한 방식으로 치명적인 다이아몬드를 가능하게 함).
supercat

@ supercat 오, 알았어. 나는 보통 자바 태그를 보지 않기 때문에 적어도 UML 답변에 대해 언급하고 있다고 생각한다고 썼다. 어쨌든, 나는 당신의 의견에 동의합니다.
BobRodes

3

다음 중 하나라도 해당 상황에 적용되는 경우 추상 클래스를 사용 하십시오.

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

이러한 상황에 해당되는 경우 인터페이스 사용을 고려하십시오 .

  1. 관련없는 클래스가 인터페이스를 구현할 것으로 기대합니다. 예를 들어 Comparable 및 Cloneable 인터페이스는 많은 관련없는 클래스에 의해 구현됩니다.
  2. 특정 데이터 유형의 동작을 지정하려고하지만 해당 동작을 구현하는 사람에 대해서는 신경 쓰지 않습니다.
  3. 다중 상속을 활용하려고합니다.

출처


2

답은 언어마다 다릅니다. 예를 들어, Java에서 클래스는 여러 인터페이스를 구현할 수 있지만 하나의 추상 클래스에서만 상속 할 수 있습니다. 따라서 인터페이스는 더 많은 유연성을 제공합니다. 그러나 이것은 C ++에서는 사실이 아닙니다.


2

저에게는 많은 경우에 인터페이스를 사용합니다. 그러나 경우에 따라 추상 클래스를 선호합니다.

OO의 클래스는 일반적으로 구현을 나타냅니다. 인터페이스에 대한 다른 구현 세부 정보를 하위에 강제로 적용하려는 경우 추상 클래스를 사용합니다.

물론 추상 클래스는 구현을 강요 할뿐만 아니라 여러 관련 클래스간에 특정 세부 정보를 공유하는 데 유용합니다.


1

기본 구현을 제공하려면 추상 클래스를 사용하십시오.


1
세바스찬 감사합니다. 그러나 기본 구현이 필요하지 않은 경우 어떻게해야합니까? 이것이 유일한 차이점이라면 추상 클래스와 인터페이스가 동일하지 않습니까? 왜 차이가 있습니까?
Chirantan

1
일부 언어에는 인터페이스가 없으므로 C ++.
jmucchiello

1

Java에서는 하나의 (추상적 인) 클래스에서 상속하여 기능을 "제공"하고 기능을 "확보"하기 위해 많은 인터페이스를 구현할 수 있습니다.


lil '힌트 : 추상 클래스와 인터페이스에서 상속
받으려면

1

순전히 상속을 기반으로, 당신은 명확하게 자손, 추상적 관계 (즉, 동물-> 고양이)를 정의하거나 가상 또는 비공개 속성, 특히 공유 상태 (인터페이스가 지원할 수없는)의 상속을 요구하는 초록을 사용합니다 ).

당신이 할 수있는 상속에 대한 구성 의존성 (dependency injection을 통해)을 시도하고 선호해야하며, 계약중인 인터페이스는 추상 테스트가 할 수없는 방식으로 단위 테스팅, 우려의 분리 및 (다양한 언어) 다중 상속을 지원합니다.


1

인터페이스가 추상 클래스보다 더 나은 흥미로운 위치는 (관련 또는 관련없는) 객체 그룹에 추가 기능을 추가해야하는 경우입니다. 기본 추상 클래스를 제공 할 수없는 경우 (예 : sealed부모이거나 이미 부모가있는 경우) 대신 더미 (빈) 인터페이스를 제공 한 다음 해당 인터페이스에 대한 확장 메소드를 작성하십시오.


0

이것은 매우 어려운 전화가 될 수 있습니다 ...

내가 줄 수있는 하나의 포인터 : 객체는 많은 인터페이스를 구현할 수 있지만 객체는 하나의 기본 클래스 만 상속 할 수 있지만 (C #과 같은 현대 OO 언어에서는 C ++에 여러 상속이 있다는 것을 알고 있지만 눈에 띄지 않습니까?)


다중 상속을 통해 Mixin을 구현할 수없는 것처럼 보일 수 있습니다. 잘 작성된 Mixin은 작업하기는 쉽지만 어딘가에 빠지지 않으면 서 작성하기가 어렵고 쓰기가 어렵습니다. Mixin은 IMO를 통해 전체적으로 꽤 시원합니다.
Martijn Laarman

실제로 나는하지 않았다, 다중 상속은 실제로 우리들 사이의 확실한 논쟁의 불꽃입니다. 사실 나는 당신의 대답을 찬성했습니다.
Martijn Laarman

내가 만들려고 한 유일한 점은 Single Inheritence로 언어를 혼합하는 방법 (C #, PHP, javascript)도 가능하지만 해키 동작이나 끈적 거리는 구문입니다. 나는 그들이 일할 때 Mixin 's를 좋아하지만 다중 상속 여부에 대해서는 여전히 결정적입니다.
Martijn Laarman

이 답변은 디자인 차이보다 구문상의 차이에 가깝습니다. 나는 그가 디자인의 차이를 요구하고 있다고 생각합니다
Pramod Setlur

0

추상 클래스는 구현을 가질 수 있습니다.

인터페이스에는 구현이 없으며 단순히 일종의 계약을 정의합니다.

언어에 따라 약간의 차이가있을 수도 있습니다. 예를 들어 C #에는 다중 상속이 없지만 클래스에서 여러 인터페이스를 구현할 수 있습니다.


"일종의 계약"이라고 말하면 웹 서비스와 같은 의미입니까?
Chirantan

기술적으로 말하면 웹 서비스는 인터페이스와 작동하지 않습니다. 계약을 통해 객체의 사용자는 해당 객체에 어떤 메소드가 있는지 알고 있습니다. 예를 들어 IMouse 인터페이스에는 Move 메서드와 왼쪽 및 오른쪽 마우스 버튼 이벤트가 있습니다.
Gerrie Schenck

-1

기본 규칙은 다음과 같습니다. "수녀"의 경우 추상 클래스 및 "동사"의 경우 인터페이스 사용

예 : car추상 클래스이며 drive인터페이스로 만들 수 있습니다.


5
이것은 말이되지 않습니다, 우리는 또한 drive자동차 의 기능을 넣을 수 있습니다 -그것은 추상 클래스입니다.
Arslan Ali
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.