이것은 일반적인 OOP 질문 일 수 있습니다. 사용법을 기준으로 인터페이스와 추상 클래스 사이의 일반적인 비교를 원했습니다.
언제 인터페이스를 사용하고 싶고 언제 추상 클래스를 사용하고 싶 습니까?
이것은 일반적인 OOP 질문 일 수 있습니다. 사용법을 기준으로 인터페이스와 추상 클래스 사이의 일반적인 비교를 원했습니다.
언제 인터페이스를 사용하고 싶고 언제 추상 클래스를 사용하고 싶 습니까?
답변:
나는 그것에 관한 기사를 썼다 :
요약 :
추상 클래스에 대해 이야기 할 때 객체 유형의 특성을 정의합니다. 객체가 무엇인지 지정 .
인터페이스에 대해 이야기하고 제공하기로 약속 한 기능을 정의 할 때 객체가 수행 할 수있는 작업에 대한 계약을 설정하는 것에 대해 이야기하고 있습니다.
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"
. 감사합니다
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”
추상 클래스는 공유 상태 또는 기능을 가질 수 있습니다. 인터페이스는 상태 또는 기능을 제공한다는 약속 일뿐입니다. 좋은 추상 클래스는 기능이나 상태를 공유 할 수 있기 때문에 다시 작성해야하는 코드의 양을 줄입니다. 인터페이스에 공유 할 정의 된 정보가 없습니다
개인적으로 저는 추상 클래스를 작성할 필요가 거의 없습니다.
대부분 추상 클래스가 잘못 사용되는 것을 본 것은 추상 클래스 작성자가 "템플릿 메소드"패턴을 사용하기 때문입니다.
"템플릿 메소드"의 문제점은 거의 항상 재진입한다는 점입니다. "파생"클래스는 구현하는 기본 클래스의 "추상"메소드뿐만 아니라 기본 클래스의 공용 메소드에 대해서도 알고 있습니다. 대부분의 경우 전화를 걸 필요는 없습니다.
(과도하게 단순화 된) 예 :
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.
}
}
이것의 문제점은 두 개념을 과도하게 결합했다는 것입니다.
위의 코드에서 이론적으로 "비교"방법의 작성자는 재진입 할 수 있습니다. 작업을 원하지 않거나 수행하지 않아도 수퍼 클래스 "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 웹 사이트 는 클래스 interface
와 abstract
클래스의 주요 차이점을 제공합니다 .
다음과 같은 경우 추상 클래스 사용을 고려하십시오 .
다음과 같은 경우 인터페이스 사용을 고려하십시오 .
Serializable
인터페이스 를 구현할 수 있습니다.예:
추상 클래스 ( IS A 관계)
리더 는 추상 클래스입니다.
BufferedReader 는Reader
FileReader 는Reader
FileReader
그리고 BufferedReader
공통의 목적으로 사용됩니다 : 데이터 읽기, 그리고 Reader
수업을 통해 관련됩니다 .
인터페이스 ( HAS A 기능)
직렬화 는 인터페이스입니다.
애플리케이션에 Serializable
인터페이스를 구현하는 두 개의 클래스가 있다고 가정하십시오.
Employee implements Serializable
Game implements Serializable
여기서 와의 Serializable
인터페이스를 통해 관계를 설정할 수는 없습니다 . 이는 다른 목적을위한 것입니다. 둘 다 상태를 직렬화 할 수 있으며 비교는 거기서 끝납니다.Employee
Game
이 게시물을 살펴보십시오.
좋아, 방금이 "그 자체"를 가지고-여기 평신도의 용어에 있습니다 (내가 틀렸다면 저를 바로 잡으십시오)-나는이 주제가 거무스름하다는 것을 알고 있지만 다른 누군가가 그것을 우연히 발견 할 수 있습니다 ...
추상 클래스를 사용하면 블루 프린트를 만들 수 있으며 모든 자손이 소유 할 속성 및 메서드를 추가로 구성 (구현) 할 수 있습니다.
반면에 인터페이스를 사용하면 지정된 이름의 속성 및 / 또는 메서드를 구현하는 모든 클래스에 존재한다고 선언 할 수 있지만 구현 방법을 지정하지는 않습니다. 또한 클래스는 많은 인터페이스를 구현할 수 있지만 ONE Abstract 클래스 만 확장 할 수 있습니다. 인터페이스는 고급 아키텍처 도구에 가깝습니다 (디자인 패턴을 파악하기 시작하면 더 명확 해짐). 초록은 두 캠프 모두에 발을 들여 놓았으며 더러운 작업도 수행 할 수 있습니다.
왜 다른 것을 사용합니까? 전자는 후손 에 대한보다 구체적인 정의를 허용합니다. 후자는 더 큰 다형성을 허용합니다 . 이 마지막 요점은 최종 사용자 / 코더에게 중요하며,이 정보를 사용 하여 필요에 맞게 다양한 조합 / 모양으로 AP I (nterface) 을 구현할 수 있습니다 .
필자는 이것이 "전구"의 순간이라고 생각한다. 인터페이스는 프로젝트의 구현을 추가하거나 API를 확장 하는 체인에서 나중에 나오는 코더의 인터페이스와 더 가깝다 .
내 두 센트 :
인터페이스는 기본적으로 모든 구현 클래스가 준수해야하는 계약을 정의합니다 (인터페이스 멤버 구현). 코드가 포함되어 있지 않습니다.
반면에 추상 클래스에는 코드가 포함될 수 있으며 상속 클래스가 구현해야하는 abstract로 표시된 일부 메소드가있을 수 있습니다.
내가 추상 클래스를 사용한 드문 상황은 상속 클래스가 추상 기본 클래스와 같이 일부 특수 클래스가 상속하는 재정의에 흥미가 없을 수있는 기본 기능이있을 때입니다.
예 (아주 초보적인 하나!)와 같은 추상 메서드가 기본 클래스라는 고객을 고려 CalculatePayment()
, CalculateRewardPoints()
과 같은 몇 가지 않는 추상적 인 방법을 GetName()
, SavePaymentDetails()
.
같은 수업을 전문 RegularCustomer
과 GoldCustomer
로부터 상속 Customer
기본 클래스 자신의 구현 CalculatePayment()
과 CalculateRewardPoints()
방법 논리를하지만, 재사용 GetName()
및 SavePaymentDetails()
방법을.
이전 버전을 사용하는 하위 클래스에 영향을주지 않고 추상 클래스 (비 추상 메소드)에 더 많은 기능을 추가 할 수 있습니다. 인터페이스에 메소드를 추가하면 새로 추가 된 인터페이스 멤버를 구현해야하므로 인터페이스를 구현하는 모든 클래스에 영향을 미칩니다.
모든 추상 멤버를 가진 추상 클래스는 인터페이스와 유사합니다.
개념이 마음에 명확하다면, 아주 간단한 일을해야 할 때.
인터페이스는 구현할 수 있지만 추상 클래스는 파생 될 수 있습니다. 둘 사이에는 약간의 차이가 있습니다. Abstract 클래스를 파생시킬 때 파생 클래스와 기본 클래스 간의 관계는 'is a'관계입니다. 예를 들어, Dog는 Animal, Sheep은 Animal입니다. 이는 파생 클래스가 기본 클래스의 일부 속성을 상속 함을 의미합니다.
인터페이스 구현의 경우 관계는 "할 수 있습니다". 예를 들어, 개는 스파이 개일 수 있습니다. 개는 서커스 개가 될 수 있습니다. 개는 경주 개가 될 수 있습니다. 이는 무언가를 얻기 위해 특정 방법을 구현한다는 것을 의미합니다.
나는 분명하기를 바랍니다.
나는 추상 클래스를 사용할 때와 인터페이스를 사용할 때에 관한 기사를 썼다. "하나의 IS-A ...와 하나의 CAN-DO ..."이외의 차이점이 훨씬 더 많습니다. 나에게, 그들은 통조림 답변입니다. 나는 그것들 중 하나를 사용해야 할 몇 가지 이유를 언급합니다. 도움이 되길 바랍니다.
나는 그것을 간결하게 만드는 가장 간결한 방법은 다음과 같다고 생각한다.
공유 속성 => 추상 클래스.
공유 기능 => 인터페이스.
간결하게 말하면 ...
추상 클래스 예 :
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
소리를 내야하지만 아직 그 구현을 모릅니다. 이 경우 인터페이스 구현을 추상화하고 해당 구현을 서브 클래스에 위임 할 수 있습니다.
마지막으로, 추상 클래스 예제에서 다른 객체의 공유 속성을 어떻게 조작 할 수 있었는지, 인터페이스 예제에서 다른 객체의 공유 기능을 호출 할 수 있었던 방법을 기억하십니까? 이 마지막 예에서 우리는 둘 다 할 수 있습니다.
인터페이스보다 추상 클래스를 선호하는 경우
언제 추상 클래스보다 인터페이스를 선호합니까?
클래스는 하나의 기본 클래스에서만 상속 될 수 있으므로 추상 클래스를 사용하여 클래스 그룹에 다형성을 제공하려면 해당 클래스에서 모두 상속해야합니다. 추상 클래스는 이미 구현 된 멤버를 제공 할 수도 있습니다. 따라서 추상 클래스에서는 일정량의 동일한 기능을 보장 할 수 있지만 인터페이스로는 불가능합니다.
다음은 구성 요소에 다형성을 제공하기 위해 인터페이스 또는 추상 클래스를 사용할지 여부를 결정하는 데 도움이되는 몇 가지 권장 사항입니다.
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx 에서 복사
다음 중 하나라도 해당 상황에 적용되는 경우 추상 클래스를 사용 하십시오.
이러한 상황에 해당되는 경우 인터페이스 사용을 고려하십시오 .
기본 구현을 제공하려면 추상 클래스를 사용하십시오.
인터페이스가 추상 클래스보다 더 나은 흥미로운 위치는 (관련 또는 관련없는) 객체 그룹에 추가 기능을 추가해야하는 경우입니다. 기본 추상 클래스를 제공 할 수없는 경우 (예 : sealed
부모이거나 이미 부모가있는 경우) 대신 더미 (빈) 인터페이스를 제공 한 다음 해당 인터페이스에 대한 확장 메소드를 작성하십시오.
이것은 매우 어려운 전화가 될 수 있습니다 ...
내가 줄 수있는 하나의 포인터 : 객체는 많은 인터페이스를 구현할 수 있지만 객체는 하나의 기본 클래스 만 상속 할 수 있지만 (C #과 같은 현대 OO 언어에서는 C ++에 여러 상속이 있다는 것을 알고 있지만 눈에 띄지 않습니까?)
추상 클래스는 구현을 가질 수 있습니다.
인터페이스에는 구현이 없으며 단순히 일종의 계약을 정의합니다.
언어에 따라 약간의 차이가있을 수도 있습니다. 예를 들어 C #에는 다중 상속이 없지만 클래스에서 여러 인터페이스를 구현할 수 있습니다.
기본 규칙은 다음과 같습니다. "수녀"의 경우 추상 클래스 및 "동사"의 경우 인터페이스 사용
예 : car
추상 클래스이며 drive
인터페이스로 만들 수 있습니다.
drive
자동차 의 기능을 넣을 수 있습니다 -그것은 추상 클래스입니다.