Replies: 3 comments
-
|
저는 추상 클래스와 인터페이스의 차이를 "문법적으로 무엇이 가능한가"보다 추상 클래스는 "is-a 관계 속에서 공통 구현과 상태를 물려주는" 도구이고, 그래서 둘 중 무엇을 쓸지는 "코드를 재사용할 게 있느냐"가 아니라 1. 두 개념의 정의추상 클래스 (Abstract Class)추상 클래스는 인스턴스화할 수 없고, 추상 메서드(구현 없는 메서드)를 가질 수 있는 클래스입니다. 일반 클래스처럼 필드(상태)와 구현된 메서드를 가질 수 있고, 자식 클래스가 추상 메서드를 구현하도록 강제합니다. public abstract class Piece {
private final Color color; // 상태를 가질 수 있음
protected Piece(Color color) {
this.color = color;
}
public boolean isSameColor(Color other) { // 공통 구현 제공
return this.color == other;
}
public abstract boolean canMove(Position from, Position to); // 자식이 구현
}인터페이스 (Interface)인터페이스는 어떤 타입이 수행할 수 있는 행위(메서드)의 집합을 선언하는 계약입니다. 전통적으로는 추상 메서드만 가졌지만, Java 8 이후 default 메서드, static 메서드를 가질 수 있게 되었고, Java 9부터는 private 메서드도 가능해졌습니다. public interface Movable {
boolean canMove(Position from, Position to); // 구현 없는 계약
default void printMoveInfo() { // Java 8+ 기본 구현 제공 가능
System.out.println("이동 가능한 객체입니다");
}
}2. Java 8 이후 문법적 경계가 흐려졌다많은 사람이 둘의 차이를 "인터페이스는 구현을 못 가지고, 추상 클래스는 가질 수 있다"로 기억하는데, 저는 이 설명이 Java 8 이후로는 부정확해졌다고 생각합니다. default 메서드가 생기면서 인터페이스도 구현을 가질 수 있게 되었기 때문입니다. 그래서 "구현 보유 여부"만으로 둘을 구분하려 하면 혼란스러워집니다. 그럼에도 여전히 분명하게 남아 있는 문법적 차이는 다음과 같습니다.
저는 이 중에서 상태를 가질 수 있는가와 다중 상속이 되는가가 가장 본질적인 차이라고 생각합니다. 이 두 가지가 결국 "무엇을 표현하는 도구인가"를 결정하기 때문입니다. 3. 본질적 차이 — 혈통 vs 역할저는 문법보다 무엇을 표현하느냐가 핵심이라고 생각합니다. 추상 클래스: is-a 관계 (혈통)추상 클래스는 "자식은 부모의 한 종류다"라는 타입 계층을 표현합니다. 자식들이 공통된 정체성과 상태, 구현을 공유할 때 적합합니다. abstract class Piece { ... }
class King extends Piece { ... } // King is-a Piece
class Tank extends Piece { ... } // Tank is-a PieceKing과 Tank은 모두 "장기 말"이라는 정체성을 공유하고, 색깔(color)이라는 공통 상태를 가집니다. 이건 혈통 관계입니다. 인터페이스: can-do 관계 (역할)인터페이스는 "이 타입은 어떤 역할을 수행할 수 있다"는 능력을 표현합니다. 정체성이 무엇이든 상관없이, 그 행위를 할 수 있으면 됩니다. interface Comparable<T> {
int compareTo(T o);
} // 비교할 수 있다
interface Serializable {
} // 직렬화될 수 있다String, Integer, LocalDate는 정체성이 전혀 다르지만 모두 Comparable을 구현합니다. "비교할 수 있다"는 능력은 혈통과 무관하기 때문입니다. 제가 던지는 질문
장기 미션을 예로 들면, King/Horse/Tank은 "Piece의 한 종류"라는 혈통이므로 추상 클래스가 어울리고, "이동 규칙을 판단할 수 있다"는 능력만 떼어낸다면 인터페이스로 표현할 수 있습니다. 4. 다중 상속 — 가장 실용적인 갈림길저는 현실에서 둘을 가르는 가장 결정적인 기준이 다중 상속 가능 여부라고 생각합니다. Java는 클래스의 다중 상속을 금지합니다(다이아몬드 문제 때문). 그래서 한 클래스는 단 하나의 추상 클래스만 상속할 수 있습니다. 반면 인터페이스는 여러 개를 구현할 수 있습니다. // 가능: 하나의 추상 클래스 + 여러 인터페이스
class Duck extends Bird implements Swimmable, Flyable {
}
// 불가능: 두 개의 추상 클래스 상속
class Duck extends Bird extends Animal { // 컴파일 에러
}이게 왜 중요하냐면, 객체는 보통 하나의 정체성을 가지지만 여러 역할을 수행하기 때문입니다. 오리는 "새"라는 하나의 정체성을 가지면서, "수영할 수 있고" "날 수 있는" 여러 역할을 동시에 가집니다. 정체성은 추상 클래스로 하나만, 역할은 인터페이스로 여럿 — 이 조합이 자연스럽습니다. 그래서 저는 "여러 무관한 타입들이 공유해야 하는 능력"이라면 무조건 인터페이스라고 생각합니다. 추상 클래스로 만들면 단일 상속 제약 때문에 그 능력을 다른 혈통에는 부여할 수 없게 됩니다. 5. 상태(필드)의 유무 — 추상 클래스만의 영역인터페이스가 default 메서드로 구현을 가질 수 있게 되었어도, 인스턴스 상태(필드)는 여전히 추상 클래스만 가질 수 있습니다. abstract class Piece {
private final Color color; // 상태 보유 가능
protected Piece(Color color) {
this.color = color;
}
}인터페이스에는 이게 둘을 구분하는 실용적 기준이 됩니다.
6. 이전 토론(LSP)과 연결지어이전에 다뤘던 "타입 계층 목적의 상속" 토론과 연결지으면 더 명확해진다고 생각합니다. 거기서 정리했던 핵심은 is-a로 보이더라도 행동 호환성(LSP)을 만족할 때만 상속하라였습니다. 추상 클래스는 상속을 강제하므로, 이 LSP의 위험을 그대로 떠안습니다. Penguin이 Bird를 상속하면서 이럴 때 인터페이스가 대안이 됩니다. "날 수 있는 능력"을 능력을 잘게 쪼개서 필요한 것만 구현하게 하는 것 — 이건 인터페이스 분리 원칙(ISP)과도 이어집니다. 그래서 저는 상속 관계가 LSP를 위반할 위험이 있다면, 추상 클래스보다 인터페이스로 능력을 분리하는 편이 안전하다고 생각합니다. 7. 언제 무엇을 선택할까제 기준을 정리하면 이렇습니다. 추상 클래스를 선택할 때
인터페이스를 선택할 때
현대 Java의 일반적 권장저는 일반적으로 인터페이스를 우선 고려하고, 공통 상태나 구현이 정말 필요할 때만 추상 클래스를 도입하는 편이 좋다고 생각합니다. 이유는 인터페이스가 다중 구현을 허용해 더 유연하고, 단일 상속이라는 귀한 자원을 소비하지 않기 때문입니다. 실제로 Java 표준 라이브러리도 이 방향입니다. 인터페이스로 계약을 먼저 두고, 추상 클래스는 구현 편의를 위한 보조 수단으로 쓰는 구조입니다. 8. 정리추상 클래스는 "같은 혈통(is-a)"을 표현하며 공통 상태와 구현을 물려주는 도구이고, 인터페이스는 "같은 능력(can-do)"을 표현하며 역할 계약을 선언하는 도구다. 선택의 기준은 문법적 가능 여부가 아니라 "혈통을 표현하는가, 역할을 표현하는가"이다.
결국 저는 둘 중 무엇이 우월하냐의 문제가 아니라, 표현하려는 관계의 성격에 맞는 도구를 고르는 문제라고 생각합니다. 혈통이면 추상 클래스, 역할이면 인터페이스 — 그리고 둘은 함께 쓰일 때 가장 강력하다고 봅니다. |
Beta Was this translation helpful? Give feedback.
-
추상클래스와 인터페이스를 사용하는 목적(실제 사용의 측면)다형성 구현이라는 목적을 위해 선택할 수 있는 두가지 옵션이라고 생각이 드는데요, 실제 사용의 측면에서는 행동의 계약만 표현할지, 아니면 계약을 구현하는 구체 클래스가 공통된 구현을 공유하는지를 기준으로 무엇을 사용할지 결정할 것 같습니다. 그래서, 공통된 구현이 공유된다면 추상클래스를 선택하고, 행동 계약(시그니처)만 공유된다면 인터페이스를 선택할 것 같습니다.
추상클래스와 인터페이스의 의미 차이 (이론적 측면)결국 추상클래스는 상속받는, 인터페이스는 구현하는 개념입니다. 그렇기 때문에 추상클래스를 구현하는 구체 클래스는 추상클래스의 자식클래스임이 의미상 맞습니다. 그래서 의미상으로 IS-A관계가 성립해야합니다. 즉, 부모클래스(여기서는 추상클래스)의 모든 계약을 자식클래스가 대체할 수 있어야하며, 부모클래스를 호출하는 클라이언트 객체는, 자식 클래스로 대체되어도 문제 없이 요청된 메시지의 응답을 받아야 합니다. 마찬가지로 인터페이스는 구현 객체들이 공통된 계약을 구현해야 하는 경우에 사용하는 것이 의미상 맞다고 생각합니다. 결국, 다른 클래스의 하위 개념이 아닌, 공통된 계약을 공유하는 객체들을 하나의 타입으로 묶기 위한 개념이라고 생각합니다. 실제 실용적인 측면에서 보았을 때실제 추상클래스를 사용할지, 인터페이스를 사용할지를 위의 이론적 측면에서 선택하는 것도 중요하지만, 결국 실용적인 측면에서 판단해야할 것 같습니다. |
Beta Was this translation helpful? Give feedback.
-
공통 필드와 메서드(기능)을 가진 클래스들의 부모 클래스를 의미합니다. 이는 클래스들이 공통으로 사용하는 필드나 메서드가 있을 때 사용합니다. 일부 메서드들은 추상클래스 내부에 미리 구현해두고, 달라지는 기능은 자식 클래스가 직접 구현하도록 구현합니다.
인터페이스는 객체가 반드시 제공해야 하는 메서드(기능)을 정의하는 클래스입니다. 어떤 클래스가 특정 기능을 할 수 있다는 것을 표현할 때 사용합니다.
두 클래스는 사용하는 목적이 다르다고 생각합니다! 추상 클래스는 클래스간 공통된 코드와 메서드, 필드를 공유하기 위한 것이고, 추가적으로 추상 클래스는 하나만 상속할 수 있지만, 인터페이스는 여러 개 구현할 수 있다고하네요! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
추상 클래스와 인터페이스
개념, 사용 목적, 차이를 자유롭게 설명해주세용!
Beta Was this translation helpful? Give feedback.
All reactions