Java의 추상 클래스 대 인터페이스


88

나는 질문을 받았으며 여기에서 내 대답을 검토하고 싶었습니다.

Q : 인터페이스를 구현하는 것보다 추상 클래스를 확장하는 것이 더 적절한 시나리오는 무엇입니까?

A : 템플릿 방법 디자인 패턴을 사용하는 경우.

제가 맞습니까 ?

질문을 명확히하지 못해 죄송합니다.
추상 클래스와 인터페이스의 기본적인 차이점을 알고 있습니다.

1) 특정 작업 (메소드 구현)에 대해 모든 하위 클래스에서 동일한 기능을 구현하고 일부 다른 작업에 대해 다른 기능 (메서드 서명 만)을 구현해야하는 경우 추상 클래스를 사용합니다.

2) 인터페이스 구현을 준수 할 수 있도록 서명을 동일하게 (그리고 구현이 다른) 경우 인터페이스를 사용하십시오.

3) 최대 하나의 추상 클래스를 확장 할 수 있지만 둘 이상의 인터페이스를 구현할 수 있습니다.

질문을 반복합니다. 위에서 언급 한 것 외에 특별히 추상 클래스를 사용해야하는 다른 시나리오가 있습니까 (하나는 템플릿 메서드 디자인 패턴이 개념적으로 이것만을 기반으로한다는 것입니다)?

인터페이스 대 추상 클래스

이 두 가지 중 하나를 선택하는 것은 실제로 원하는 작업에 따라 다르지만 운 좋게도 Erich Gamma가 도움이 될 수 있습니다.

항상 트레이드 오프가 있습니다. 인터페이스는 기본 클래스와 관련하여 자유를 제공하고 추상 클래스는 나중에 새 메서드를 추가자유를 제공합니다 . – 에리히 감마

당신은 가서 다른 많은 것들을 변경하지 않고도 인터페이스를 변경할 수 있는 유일한 방법이 항상 좋은 일이되지 않을 수 있습니다 완전히 새로운 인터페이스를 생성하는 것입니다 피할 수 있도록 코드에서.

Abstract classes밀접하게 관련된 객체에 주로 사용되어야합니다. Interfaces관련없는 클래스에 대한 공통 기능을 제공하는 데 더 좋습니다.




이것은 중복되지 않습니다. OP는 인터페이스를 구현하기보다 추상 클래스 를 확장 할 때를 알고 싶어합니다 . 그는 추상 클래스 나 인터페이스를 언제 작성해야하는지 알고 싶지 않습니다. 그의 추상 클래스와 인터페이스는 이미 작성되었습니다. Hd는 확장 또는 구현 여부를 알고 싶어합니다.
Shiplu Mokaddim

1
@ shiplu.mokadd.im 차이가없는 구별입니다. 확장하지 않고는 추상 클래스를 사용할 수 없습니다. 여기서 당신의 nitpicking은 완전히 무의미한 것 같습니다.
론의 후작

답변:


87

인터페이스를 사용하는 경우

인터페이스를 사용하면 누군가가 처음부터 인터페이스를 구현하거나 원래 또는 기본 목적이 인터페이스와 상당히 다른 다른 코드로 인터페이스를 구현할 수 있습니다. 그들에게 당신의 인터페이스는 단지 부수적 인 것이고, 당신의 패키지를 사용할 수 있도록 그들의 코드에 추가해야하는 것입니다. 단점은 인터페이스의 모든 메서드가 공용이어야한다는 것입니다. 모든 것을 노출하고 싶지 않을 수도 있습니다.

추상 클래스를 사용하는 경우

대조적으로 추상 클래스는 더 많은 구조를 제공합니다. 일반적으로 일부 기본 구현을 정의하고 전체 구현에 유용한 도구를 제공합니다. 문제는 그것을 사용하는 코드가 클래스를 기본으로 사용해야한다는 것입니다. 패키지를 사용하려는 다른 프로그래머가 이미 자체 클래스 계층 구조를 독립적으로 개발 한 경우 매우 불편할 수 있습니다. Java에서 클래스는 하나의 기본 클래스에서만 상속 할 수 있습니다.

둘 다 사용하는 경우

인터페이스와 추상 클래스의 장점을 모두 제공 할 수 있습니다. 구현자는 선택한 경우 추상 클래스를 무시할 수 있습니다. 이렇게하는 유일한 단점은 인터페이스 이름을 통해 메서드를 호출하는 것입니다. 추상 클래스 이름을 통해 호출하는 것보다 약간 느립니다.


나는 영업 이익은 때 알고 싶은 생각 확장 인터페이스 추상 클래스를보다는 구현
Shiplu Mokaddim

@ shiplu.mokadd.im 실제로 OP는 매우 구체적인 질문을했는데 그에 대한 대답은 '예'또는 '아니요'입니다.
론의 후작

4
네가 옳아. 그러나 그래서 우리는 적절한 설명과 함께 예 / 아니오로 대답합니다.
Shiplu Mokaddim

1
@ shiplu.mokadd.im 나는 그것이 당신에게 그의 질문을 잘못 진술 할 수있는 면허를 어떻게 주는지 모르겠습니다.
론의 후작

오직이 하나의 문장에 근거하여 If we are using template method design pattern우리는 말을하지 못할 YES또는NO
DivineDesert

31

질문을 반복합니다. 위에서 언급 한 것 외에 특별히 추상 클래스를 사용해야하는 다른 시나리오가 있습니다 (하나는 템플릿 메서드 디자인 패턴이 개념적으로 이것만을 기반으로한다는 것입니다)

예, JAXB를 사용하는 경우. 인터페이스를 좋아하지 않습니다. 추상 클래스를 사용하거나 제네릭으로이 제한을 해결해야합니다.

개인 블로그 게시물에서 :

상호 작용:

  1. 클래스는 여러 인터페이스를 구현할 수 있습니다.
  2. 인터페이스는 코드를 전혀 제공 할 수 없습니다.
  3. 인터페이스는 공개 정적 최종 상수 만 정의 할 수 있습니다.
  4. 인터페이스는 인스턴스 변수를 정의 할 수 없습니다.
  5. 새 메서드를 추가하면 클래스 구현에 파급 효과가 있습니다 (디자인 유지 관리).
  6. JAXB는 인터페이스를 처리 할 수 ​​없습니다.
  7. 인터페이스는 추상 클래스를 확장하거나 구현할 수 없습니다.
  8. 모든 인터페이스 메서드는 공용입니다.

일반적으로 인터페이스는 계약을 정의하는 데 사용되어야합니다 (어떻게 달성해야하는지가 아니라 달성해야하는 내용).

초록 클래스 :

  1. 클래스는 최대 하나의 추상 클래스를 확장 할 수 있습니다.
  2. 추상 클래스는 코드를 포함 할 수 있습니다.
  3. 추상 클래스는 정적 및 인스턴스 상수를 모두 정의 할 수 있습니다 (최종).
  4. 추상 클래스는 인스턴스 변수를 정의 할 수 있습니다.
  5. 기존 추상 클래스 코드를 수정하면 클래스 확장에 파급 효과가 있습니다 (구현 유지 관리).
  6. 추상 클래스에 새 메서드를 추가해도 클래스 확장에 파급 효과가 없습니다.
  7. 추상 클래스는 인터페이스를 구현할 수 있습니다.
  8. 추상 클래스는 개인 및 보호 메서드를 구현할 수 있습니다.

추상 클래스는 (부분) 구현에 사용되어야합니다. API 계약이 구현되어야하는 방식을 제한하는 수단이 될 수 있습니다.


3
인터페이스 # 8 용 Java 8에서는 defaultstatic메소드도 가질 수 있습니다 .
초보 사용자


10

여기에는 훌륭한 답변이 많이 있지만 인터페이스와 추상 클래스를 모두 사용하는 것이 가장 좋은 방법이라는 것을 종종 발견합니다. 이 인위적인 예를 고려하십시오.

당신은 투자 은행의 소프트웨어 개발자이고 시장에 주문하는 시스템을 구축해야합니다. 귀하의 인터페이스는 거래 시스템 하는 일에 대한 가장 일반적인 아이디어를 포착합니다 .

1) Trading system places orders
2) Trading system receives acknowledgements

인터페이스에서 캡처 할 수 있습니다. ITradeSystem

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

이제 영업 데스크 및 기타 비즈니스 라인에서 일하는 엔지니어는 시스템과 인터페이스 하여 기존 앱에 주문 배치 기능을 추가 할 수 있습니다 . 그리고 당신은 아직 건축을 시작하지 않았습니다! 이것이 인터페이스의 힘입니다.

그래서 계속해서 주식 거래자를 위한 시스템을 구축하십시오 . 그들은 당신의 시스템에 값싼 주식을 찾는 기능이 있다고 들었고 그것을 시험해보고 싶어합니다! 이 동작을라는 메서드로 캡처 findGoodDeals()하지만 시장에 연결하는 데 관련된 복잡한 요소가 많이 있다는 것도 알고 있습니다. 예를 들어, 당신은SocketChannel ,

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

구체적인 구현에는와 같은 지저분한 메소드가 많이 connectToMarket()있지만findGoodDeals() 모든 상인이 실제로 걱정입니다.

이제 여기에서 추상 클래스가 작동합니다. 상사는 통화 거래자들도 귀하의 시스템을 사용하기를 원한다고 알려줍니다. 통화 시장을 보면 배관이 주식 시장과 거의 동일하다는 것을 알 수 있습니다. 실제로 connectToMarket()외환 시장에 연결하기 위해 그대로 재사용 할 수 있습니다. 그러나 findGoodDeals()통화 분야에서는 훨씬 다른 개념입니다. 따라서 코드베이스를 바다 건너 외환 마법사 에게 전달하기 전에 먼저 abstract클래스 로 리팩토링하여 구현되지 않은 상태로 findGoodDeals()둡니다.

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

주식 거래 시스템 findGoodDeals()은 이미 정의한대로 구현 됩니다.

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

하지만 이제 FX 전문가는 단순히 findGoodDeals()통화 구현을 제공함으로써 시스템을 구축 할 수 있습니다 . 그녀는 소켓 연결이나 인터페이스 메서드를 다시 구현할 필요가 없습니다!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

인터페이스 프로그래밍은 강력하지만 유사한 응용 프로그램은 거의 동일한 방식으로 메서드를 다시 구현하는 경우가 많습니다. 추상 클래스를 사용하면 인터페이스의 성능을 유지하면서 단순화를 피할 수 있습니다.

참고 :findGreatDeals() 인터페이스의 일부가 아닌 이유 가 궁금 할 수 있습니다. 인터페이스는 거래 시스템의 가장 일반적인 구성 요소를 정의합니다. 다른 엔지니어는 좋은 거래를 찾는 데 신경 쓰지 않는 완전히 다른 거래 시스템을 개발할 수 있습니다. 이 인터페이스는 영업 데스크가 시스템과도 인터페이스 할 수 있도록 보장하므로 "대가"와 같은 애플리케이션 개념과 인터페이스를 얽 히지 않는 것이 좋습니다.


6

추상 클래스 또는 인터페이스를 사용해야합니까?

다음 명령문 중 하나가 사용 사례에 적용되는 경우 추상 클래스 사용을 고려하십시오.

밀접하게 관련된 여러 클래스간에 코드를 공유하려고합니다.

추상 클래스를 확장하는 클래스에는 많은 공통 메서드 또는 필드가 있거나 public 이외의 액세스 수정자가 필요합니다 (예 : protected 및 private).

비 정적 또는 비 최종 필드를 선언하려고합니다. 이를 통해 자신이 속한 개체의 상태에 액세스하고 수정할 수있는 메서드를 정의 할 수 있습니다.

다음 문 중 하나가 사용 사례에 적용되는 경우 인터페이스 사용을 고려하십시오.

관련없는 클래스가 인터페이스를 구현할 것으로 예상합니다. 예를 들어, Comparable 및 Cloneable 인터페이스는 관련없는 많은 클래스에 의해 구현됩니다.

특정 데이터 유형의 동작을 지정하고 싶지만 해당 동작을 구현하는 사람은 신경 쓰지 않습니다.

유형의 다중 상속을 활용하려고합니다.

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


4

Java 8 릴리스와의 인터페이스를위한 새로운 기능이 추가되면서 지난 3 년 동안 상황이 많이 변경되었습니다.

인터페이스의 오라클 문서 페이지 에서 :

인터페이스는 상수, 메서드 서명, 기본 메서드, 정적 메서드 및 중첩 형식 만 포함 할 수있는 클래스와 유사한 참조 형식입니다. 메서드 본문은 기본 메서드 및 정적 메서드에 대해서만 존재합니다.

질문에서 인용했듯이 추상 클래스는 템플릿 메서드 패턴에 가장 적합합니다. 골격을 만들어야하는 . 여기에서는 인터페이스를 사용할 수 없습니다.

인터페이스보다 추상 클래스를 선호하는 또 다른 고려 사항 :

기본 클래스에는 구현이 없으며 하위 클래스 만 자체 구현을 정의하면됩니다. 하위 클래스와 상태를 공유하고 싶기 때문에 인터페이스 대신 추상 클래스가 필요합니다.

추상 클래스는 관련 클래스간에 "is a"관계를 설정하고 인터페이스는 관련없는 클래스간에 "has a"기능을 제공합니다 .


질문의 두 번째 부분에 관해서는 java-8 이전의 Java를 포함한 대부분의 프로그래밍 언어에 유효합니다. 릴리스

항상 트레이드 오프가 있습니다. 인터페이스는 기본 클래스와 관련하여 자유를 제공하고 추상 클래스는 나중에 새 메서드를 추가 할 자유를 제공합니다. – 에리히 감마

코드에서 다른 많은 사항을 변경하지 않고는 인터페이스를 변경할 수 없습니다.

위의 두 가지 고려 사항으로 이전에 인터페이스하는 것보다 추상 클래스를 선호하는 경우 기본 메서드 가 인터페이스에 강력한 기능을 추가 했기 때문에 지금 다시 생각해야합니다 .

기본 메서드를 사용하면 라이브러리의 인터페이스에 새 기능을 추가하고 해당 인터페이스의 이전 버전 용으로 작성된 코드와 바이너리 호환성을 보장 할 수 있습니다.

인터페이스와 추상 클래스 중 하나를 선택하려면 Oracle 문서 페이지에서 다음을 인용 하십시오 .

추상 클래스는 인터페이스와 유사합니다. 인스턴스화 할 수 없으며 구현 여부에 관계없이 선언 된 메서드 혼합이 포함될 수 있습니다. 그러나 추상 클래스를 사용하면 정적 및 최종 필드가 아닌 필드를 선언하고 공용, 보호 및 개인 구체적인 메서드를 정의 할 수 있습니다.

인터페이스를 사용하면 모든 필드가 자동으로 public, static 및 final이되고 선언하거나 정의하는 모든 메서드 (기본 메서드)가 공용입니다. 또한 추상인지 여부에 관계없이 하나의 클래스 만 확장 할 수 있지만 여러 인터페이스를 구현할 수 있습니다.

자세한 내용은 다음 관련 질문을 참조하십시오.

인터페이스 대 추상 클래스 (일반 OO)

인터페이스와 추상 클래스의 차이점을 어떻게 설명해야합니까?

요약하자면 , 균형은 현재 인터페이스쪽으로 기울어지고 있습니다 .

위에서 언급 한 것 외에 특별히 추상 클래스를 사용해야하는 다른 시나리오가 있습니까 (하나는 템플릿 메서드 디자인 패턴이 개념적으로 이것만을 기반으로한다는 것입니다)?

일부 디자인 패턴은 템플릿 메서드 패턴과 별도로 인터페이스를 통해 추상 클래스를 사용합니다.

창조 패턴 :

Abstract_factory_pattern

구조 패턴 :

Decorator_pattern

행동 패턴 :

Mediator_pattern


"추상 클래스는 관련 클래스간에"is a "관계를 설정하고 인터페이스는 관련없는 클래스간에"가 "기능을 제공합니다."
Gabriel

3

당신은 정확하지 않습니다. 많은 시나리오가 있습니다. 단 하나의 8 단어 규칙으로 줄이는 것은 불가능합니다.


1
당신이 모호하지 않는 한; 때마다 당신이 할 수있는 인터페이스를 사용)
피터 Lawrey

@PeterLawrey 그래, 원형 인수 ;-) 당신을 느리게하지 않습니다
론의 후작

이것은 결국 "스택 오버플로"입니다. ;) 내 요점은 더 간단한 인터페이스를 사용할 수 있다면 그렇게한다는 것입니다. 그렇지 않으면 추상 클래스를 사용할 수밖에 없습니다. 나는 그것이 매우 복잡하다고 생각하지 않습니다.
Peter Lawrey 2012

나는 당신이 더 건설적인 아이디어를 제공 할 수 있다고 생각합니다. 몇 가지 대표적인 시나리오에 대한 이야기처럼 /
Adams.H

3

가장 짧은 대답은 검색하는 기능 중 일부가 이미 구현되어있을 때 추상 클래스를 확장 하는 것입니다.

인터페이스를 구현하는 경우 모든 메소드를 구현해야합니다. 그러나 추상 클래스의 경우 구현해야하는 메서드 수가 적을 수 있습니다.

에서 템플릿 디자인 패턴 행동이 정의가 있어야합니다. 이 동작은 추상적 인 다른 방법에 따라 다릅니다. 하위 클래스를 만들고 이러한 메서드를 정의하여 실제로 주요 동작을 정의합니다. 인터페이스는 아무것도 정의하지 않고 선언하기 때문에 기본 동작은 인터페이스에있을 수 없습니다. 따라서 템플릿 디자인 패턴은 항상 추상 클래스와 함께 제공됩니다. 동작의 흐름을 그대로 유지하려면 추상 클래스를 확장해야하지만 기본 동작을 재정의하지 마십시오.


Pure Virtual Function에 대한 추가 참조 는 추상 클래스 및 인터페이스의 수렴 , Pure virtual functions can also be used where the method declarations are being used to define an interface - similar to what the interface keyword in Java explicitly specifies. In such a use, derived classes will supply all implementations. In such a design pattern, the abstract class which serves as an interface will contain only pure virtual functions, but no data members or ordinary methods. Part (1/2) 에 대한 더 많은 통찰력을 추가 할 것입니다.
Abhijeet 2015

Part (2/2) Abstract Class와 Interface의 발산은no data members or ordinary methods [Abstract Class에서] 위의 마지막 줄에 설명되어 있습니다.
Abhijeet 2015

3

제 생각에 기본적인 차이점은 바로 그것 an interface can't contain non abstract methods while an abstract class can입니다. 따라서 하위 클래스가 공통 동작을 공유하는 경우이 동작은 슈퍼 클래스에서 구현되어 하위 클래스에서 상속 될 수 있습니다.

또한 "자바의 소프트웨어 아키텍처 설계 패턴"책에서 다음을 인용했습니다.

"Java 프로그래밍 언어에서는 다중 상속을 지원하지 않습니다. 즉, 클래스는 하나의 단일 클래스에서만 상속 할 수 있습니다. 따라서 상속은 반드시 필요한 경우에만 사용해야합니다. 가능하면 공통 동작을 나타내는 메서드를 다음에서 선언해야합니다. 다른 구현 자 클래스에 의해 구현되는 Java 인터페이스의 형식입니다. 그러나 인터페이스는 메소드 구현을 제공 할 수 없다는 한계가 있습니다. 이는 인터페이스의 모든 구현자가 인터페이스에 선언 된 모든 메소드를 명시 적으로 구현해야 함을 의미합니다. 메서드는 기능의 변하지 않는 부분을 나타내며 모든 구현 자 클래스에서 정확히 동일한 구현을 가지므로 코드가 중복됩니다.다음 예제는 중복 메소드 구현을 요구하지 않고 이러한 경우에 추상 상위 클래스 패턴을 사용하는 방법을 보여줍니다. "


2

추상 클래스는 두 가지 중요한 측면에서 인터페이스와 다릅니다.

  • 선택한 방법에 대한 기본 구현을 제공합니다 (답변에 포함됨).
  • 추상 클래스는 상태 (인스턴스 변수)를 가질 수 있으므로 인터페이스 대신 사용하려는 또 다른 상황입니다.

인터페이스는 변수를 가질 수 있지만 기본적으로 최종입니다.
Tomasz Mularczyk

1

이것은 좋은 질문입니다.이 두 가지는 비슷하지는 않지만 재 작성과 같은 동일한 이유로 사용할 수 있습니다. 만들 때 인터페이스를 사용하는 것이 가장 좋습니다. 수업에 관해서는 디버깅에 좋습니다.


0

Abstract classes should be extended when you want to some common behavior to get extended. Abstract 수퍼 클래스는 공통 동작을 가지며 하위 클래스가 구현해야하는 추상 메서드 / 특정 동작을 정의합니다.

Interfaces allows you to change the implementation anytime allowing the interface to be intact.


0

이것이 제 이해입니다. 도움이되기를 바랍니다.

추상 클래스 :

  1. 상속 된 멤버 변수를 가질 수 있음 (인터페이스에서 수행 할 수 없음)
  2. 생성자를 가질 수 있음 (인터페이스는 할 수 없음)
  3. 그 메서드는 모든 가시성을 가질 수 있습니다 (예 : private, protected 등-모든 인터페이스 메서드는 공용입니다).
  4. 정의 된 메서드 (구현이있는 메서드)를 가질 수 있습니다.

인터페이스 :

  1. 변수를 가질 수 있지만 모두 공개 정적 최종 변수입니다.
    • 정적 범위로 변경되지 않는 상수 값
    • 비 정적 변수에는 인스턴스가 필요하며 인터페이스를 인스턴스화 할 수 없습니다.
  2. 모든 메서드는 추상 (추상 메서드에는 코드 없음)
    • 모든 코드는 특정 인터페이스를 구현하는 클래스에 실제로 작성되어야합니다.

0

초록 및 인터페이스 사용 :

하나는 "Is-A-Relationship"이 있고 다른 하나는 "Has-A-Relationship"이 있습니다.

기본 속성은 추상으로 설정되어 있으며 추가 속성은 인터페이스를 통해 표현할 수 있습니다.

예 :-> 인간에게는 식사, 수면 등의 기본 속성이 있지만 수영, 놀이 등과 같은 다른 커리큘럼 활동이있는 경우 인터페이스로 표현할 수 있습니다.

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