Stack은 왜 상속의 실패 사례일까?

2024. 12. 12. 21:50·💻 Dev/Java & OOP

Java에서 Stack 클래스는 종종 "상속의 실패 사례"나 "디자인이 망가진 클래스"로 언급된다.
뭐 때문인지 알아보자!

 

Vector를 잘못 상속받았다.

Stack 클래스의 가장 큰 문제는 Vector 클래스를 상속받았다는 점이다.


Stack의 선언을 보면 다음과 같다.

public class Stack<E> extends Vector<E> {

Stack은 LIFO(Last In, First Out) 방식의 스택 자료구조를 구현하기 위해 설계되었지만, Vector는 일반적인 동적 배열을 나타낸다.

 

근데 뭐가 문제라는걸까? 🤔

Stack이 Vector를 상속받았다는 것은 Vector의 모든 메서드를 사용할 수 있다는 것을 말한다.

 

`Vector`는 일반적인 동적 배열 자료구조기 때문에 원래 스택에서는 허용되지 않을 중간에 요소를 추가하거나 삭제하는 등의 동작이 가능하다.

 

Stack<Integer> stack = new Stack<>();
stack.add(0);
stack.add(1);
stack.insertElementAt(99, 0); // 스택의 첫 번째 위치에 99 삽입

System.out.println(stack); // 출력: [99, 0, 1]

위처럼 Stack 클래스에서 비스택적인 동작을 허용하게 된 것이다.

스택이 쌓은 데이터들 사이에 갑자기 벡터 스킬을 사용하는 애가 와서 중간에 새치기를 하는 것이다. 

 

왜 이런 일이 생겼을까?

Stack과 Vector는 둘 다 JDK 1.0에 추가된 클래스이다. 당시에는 객체 지향 설계 원칙이 지금처럼 엄격히 적용되지 않았고, 이후 자바가 하위 호환성을 유지해야 하는 이유로 이 설계가 변경되지 못했다고 한다.

 

 

상속 대신 조합이 적합했다.

상속은 클래스 간의 "is-a" 관계를 표현해야 한다.(정확히는 is a kind of)

하지만 Stack과 Vector의 관계는 "is-a"가 아니라 "uses-a" 관계에 더 가깝다.

 

"Uses-a" 관계란 객체 지향 프로그래밍에서 '한 클래스가 다른 클래스를 사용'하는 관계를 말한다.

 

다시 말해 상속 대신 내부에서 다른 클래스의 객체를 멤버 변수로 포함하는 방식(조합, Composition)을 사용하는 게 적절했다.

public class Stack<T> {
    private Vector<T> vector;

    public Stack() {
        this.vector = new Vector<>();
    }

    public void push(T item) {
        vector.add(item);
    }

    public T pop() {
        return vector.remove(vector.size() - 1);
    }

    public T peek() {
        return vector.get(vector.size() - 1);
    }

    public boolean isEmpty() {
        return vector.isEmpty();
    }

    public int size() {
        return vector.size();
    }
}

이렇게 스택의 내부 데이터 구조로 Vector를 사용하면서 스택 자료구조에 필요한 메서드만 제공하는 것이다.

 

 

해결법은? ArrayDeque를 사용하자

자바 컬렉션 프레임워크에서는 Stack 대신 Deque인터페이스(특히 ArrayDeque 클래스)를 사용할 것을 권장한다.

 

ArrayDeque는 스택에 필요한 모든 작업을 제공하며, Stack보다 빠르다. 또 Stack은 초기 크기를 지정할 수 없었지만 ArrayDeque은 생성자로 초기 크기를 지정할 수 있다.

public class ArrayDequeTest {
    public static void main(String[] args) {
        Deque<Integer> stack = new ArrayDeque<>();

        stack.push(10);
        stack.push(20);
        stack.push(30);

        System.out.println("Top of the stack: " + stack.peek()); // Output: 30

        // Pop elements from the stack
        System.out.println("Popped: " + stack.pop()); // Output: 30
        System.out.println("Popped: " + stack.pop()); // Output: 20

        System.out.println("Stack size: " + stack.size()); // Output: 1
    }
}

이렇게 `ArratDeque`를 사용하면 더 효율적인 스택 및 큐 동작이 가능하고 불필요한 상속 문제를 피할 수 있다!

 

 

 

 

참고
자바의 Stack 클래스는 왜 사용하지 않는 걸까?
상속보다는 컴포지션을 사용하라(Feat. Stack)

저작자표시 비영리 (새창열림)

'💻 Dev > Java & OOP' 카테고리의 다른 글

자바 직렬화(Java Serializable)  (0) 2024.12.27
자바는 왜 Lambda&Stream을 도입했을까? feat.함수형 프로그래밍  (0) 2024.12.26
리플렉션(Reflection)으로 DI 구현해보기 +단점  (0) 2024.12.22
System.out.println을 실무에서 사용하면 안되는 이유  (0) 2024.12.05
가비지 컬렉터(GC)의 Roots  (0) 2024.12.04
Out-of-Memory(OOM)는 왜 발생하고, 어떻게 예방할까?  (0) 2024.11.30
'💻 Dev/Java & OOP' 카테고리의 다른 글
  • 자바는 왜 Lambda&Stream을 도입했을까? feat.함수형 프로그래밍
  • 리플렉션(Reflection)으로 DI 구현해보기 +단점
  • System.out.println을 실무에서 사용하면 안되는 이유
  • 가비지 컬렉터(GC)의 Roots
현주먹
현주먹
대구 불주먹 출신 현주먹의 개발.log
  • 현주먹
    현주먹의 개발로그
    현주먹
  • 전체
    오늘
    어제
    • 전체글 (167)
      • 👶🏻 CS (15)
        • Operating System (8)
        • Database (4)
        • Data Structure (2)
        • Software Engineering (1)
      • 💻 Dev (54)
        • Java & OOP (24)
        • Spring (4)
        • JPA (5)
        • Test Code (1)
        • Database (1)
        • JSP & Servlet (13)
        • Etc (6)
      • 💡 Algorithm (25)
        • 인프런 (9)
        • 백준 (16)
      • 🛠 DevOps & Tool (11)
        • Linux (4)
        • AWS (1)
        • Git (2)
        • Etc (4)
      • 📝 끄적끄적 (62)
        • 후기 및 회고 (5)
        • TDD, 클린 코드 with Java 17기 (3)
        • F-Lab (23)
        • 🖥️ 자바의 정석 (11)
        • 📖 Clean Code (3)
        • 항해99 코테 스터디 (11)
        • 📖 가상 면접 사례로 배우는 대규모 시스템 설계 .. (5)
  • 블로그 메뉴

    • 🐈‍⬛ GitHub
    • TIL repository
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 태그

    티스토리챌린지
    til
    TDD 클린 코드 with Java
    항해99
    코딩테스트준비
    jsp
    PostGreSQL함수
    F-Lab
    객체지향
    자바의정석
    데브클럽
    99클럽
    오라클
    ==와 equals()
    C
    백준
    자바의신절판
    백준10250
    NextSTEP
    오블완
    f-lab 후기
    JPA
    인프런 단어뒤집기
    에프랩
    에프랩 후기
    로또 미션
    코테스터디
    인프런 특정문자뒤집기
    개발자취업
    개발자멘토링
  • hELLO· Designed By정상우.v4.10.2
현주먹
Stack은 왜 상속의 실패 사례일까?
상단으로

티스토리툴바