development

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

big-blog 2020. 10. 12. 07:47
반응형

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


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

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

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

제가 맞습니까 ?

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

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

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

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

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

인터페이스 대 추상 클래스

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

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

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

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


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

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

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

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

둘 다 사용하는 경우

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


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

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

개인 블로그 게시물에서 :

상호 작용:

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

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

초록 클래스 :

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

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


인터페이스는 모든 클래스가 동일한 구조를 가지고 있지만 완전히 다른 기능을 갖는 시나리오가있을 때 사용됩니다.

추상 클래스는 모든 클래스가 동일한 구조를 갖지만 일부는 동일하고 일부 다른 기능을 갖는 시나리오가있을 때 사용됩니다.

기사보기 : http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html


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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

창조 패턴 :

Abstract_factory_pattern

구조 패턴 :

Decorator_pattern

행동 패턴 :

Mediator_pattern


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

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

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

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

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

다음 명령문이 상황에 적용되는 경우 인터페이스 사용을 고려하십시오.

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

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

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

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


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


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

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

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


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

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

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


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

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

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

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

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()모든 거래자가 실제로 관심을 기울입니다.

Now here's where abstract classes come into play. Your boss informs you that currency traders also want to use your system. And looking at currency markets, you see the plumbing is nearly identical to stock markets. In fact, connectToMarket() can be reused verbatim to connect to foreign exchange markets. However, findGoodDeals() is a much different concept in the currency arena. So before you pass off the codebase to the foreign exchange wiz kid across the ocean, you first refactor into an abstract class, leaving findGoodDeals() unimplmented

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>
    }

Your stock trading system implements findGoodDeals() as you've already defined,

public class StockTradeSystem extends ABCTradeSystem{    

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

but now the FX whiz kid can build her system by simply providing an implementation of findGoodDeals() for currencies; she doesn't have to reimplement socket connections or even the interface methods!

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);
    }

Programming to an interface is powerful, but similar applications often re-implement methods in nearly identical ways. Using an abstract class avoids reimplmentations, while preserving the power of the interface.

Note: one may wonder why findGreatDeals() isn't part of the interface. Remember, the interface defines the most general components of a trading system. Another engineer may develop a COMPLETELY DIFFERENT trading system, where they don't care about finding good deals. The interface guarantees that the sales desk can interface to their system as well, so it's preferable not to entangle your interface with application concepts like "great deals".


This is a good question The two of these are not similar but can be use for some of the same reason, like a rewrite. When creating it is best to use Interface. When it comes down to class, it is good for debugging.


Abstract classes should be extended when you want to some common behavior to get extended. The Abstract super class will have the common behavior and will define abstract method/specific behavior which sub classes should implement.

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


This is my understanding, hope this helps

Abstract classes:

  1. Can have member variables that are inherited (can’t be done in interfaces)
  2. Can have constructors (interfaces can’t)
  3. Its methods can have any visibility (ie: private, protected, etc - whereas all interface methods are public)
  4. Can have defined methods (methods with an implementation)

Interfaces:

  1. Can have variables, but they are all public static final variables
    • constant values that never change with a static scope
    • non static variables require an instance, and you can’t instantiate an interface
  2. All methods are abstract (no code in abstract methods)
    • all code has to be actually written in the class that implements the particular interface

Usage of abstract and interface:

One has "Is-A-Relationship" and another one has "Has-A-Relationship"

The default properties has set in abstract and extra properties can be expressed through interface.

Example: --> In the human beings we have some default properties that are eating, sleeping etc. but if anyone has any other curricular activities like swimming, playing etc those could be expressed by Interface.

참고URL : https://stackoverflow.com/questions/10040069/abstract-class-vs-interface-in-java

반응형