List - 리스트 추상화 1 - 인터페이스 도입

2024. 5. 22. 09:14김영한 Java/컬렉션 프레임워크

자바 기본편에서 학습한 다형성과 OCP원칙을 가장 잘 활용할 수 있는 곳 중에 하나가 바로 자료 구조이다.

 

List 자료구조

순서가 있고, 중복을 허용하는 자료 구조를 리스트(List)라고 한다.

우리가 지금까지 만든 MyArrayList와 MyLinkedList는 내부 구현만 다를 뿐 같은 기능을 제공하는 리스트이다. 

물론 내부 구현이 다르기 때문에 상황에 따라 성능은 달라질 수 있다. 핵심은 사용자 입장에서 보면 같은 기능을 제공한다는 것이다. 이 둘의 공통 기능을 인터페이스로 뽑아서 추상화 하면 다형성을 활용한 다양한 이득을 얻을 수 있다.

 

같은 기능을 제공하는 메서드를 MyList인터페이스로 뽑아보자.

 

MyList

package collection.list;

public interface MyList<E> {
    int size();

    void add(E e);

    void add(int index, E e);

    E get(int index);

    E set(int index, E element);

    E remove(int index);

    int indexOf(E o);

}

 

MyArrayList

package collection.list;

import java.util.Arrays;

public class MyArrayList<E> implements MyList<E> {
    private Node<E> first;
    private int size = 0;
    @Override
    public void add(E e) {
        Node<E> newNode = new Node<>(e);
        if (first == null) {
            first
                    = newNode;
        }
        else {
            Node<E> lastNode = getLastNode();
            lastNode.next = newNode;
        }
        size++;
    }
    private Node<E> getLastNode() {
        Node<E> x = first;
        while (x.next != null) {
            x
                    = x.next;
        }
        return x;
    }
    @Override
    public void add(int index, E e) {
        Node<E> newNode = new Node<>(e);
        if (index == 0) {
            newNode.next = first;
            first
                    = newNode;
        }
        else {
            Node<E> prev = getNode(index - 1);
            newNode.next = prev.next;
            prev.next = newNode;
        }
        size++;
    }
    @Override
    public E set(int index, E element) {
        Node<E> x = getNode(index);
        E oldValue = x.item;
        x.item = element;
        return oldValue;
    }
    @Override
    public E remove(int index) {
        Node<E> removeNode = getNode(index);
        E removedItem = removeNode.item;
        if (index == 0) {
            first= removeNode.next;
        }

 else {
            Node<E> prev = getNode(index - 1);
            prev.next = removeNode.next;
        }
        removeNode.item = null;
        removeNode.next = null;
        size--;
        return removedItem;
    }
    @Override
    public E get(int index) {
        Node<E> node = getNode(index);
        return node.item;
    }
    private Node<E> getNode(int index) {
        Node<E> x = first;
        for (int i = 0; i < index; i++) {
            x
                    = x.next;
        }
        return x;
    }
    @Override
    public int indexOf(E o) {
        int index = 0;
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
        return -1;
    }
    @Override
    public int size() {
        return size;
    }
    @Override
    public String toString() {
        return "MyLinkedListV1{" +
                "first=" + first +
                ", size=" + size +
                '}';
    }
    private static class Node<E> {
        E item;
        Node<E> next;
        public Node(E item) {
            this.item = item;
        }
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            Node<E> temp = this;
            sb.append("[");
            while (temp != null) {
                sb.append(temp.item);
                if (temp.next != null) {
                    sb.append("->");
                }
                temp
                        = temp.next;
            }
            sb.append("]");
            return sb.toString();
        }
    }


}