본문 바로가기

디자인 패턴/디자인 패턴

[디자인 패턴] 템플릿 메소드 패턴 - compareTo

책을 공부하며 새로운 문제를 만들고 구현한것을 기록한 게시글입니다.

(이해한 내용을 바탕으로 작성했기 때문에, 내용이 정확하지않고 틀린부분이 있을수있으며, 예시가 패턴을 사용하기에 알맞지 않을수도있습니다)

 


템플릿 메소드 패턴

알고리즘의 구조를 정의한다. 이때 일부 단계는 서브클래스에서 구현할수도있다.

템플릿 메소드패턴은, 알고리즘의 구조는 유지하면서 특정단계만 서브클래스에서 구현하도록 할수있다.

 

스트래티지 패턴과 알고리즘군을 캡슐화한다는점이 유사하지만, 스트래티지 패턴은 구성을, 템플릿 메소드 패턴은 상속을 이용한다.

 


문제

Java의 Collections API에는 sort메소드가 있다. Collections에 포함되어있는 ArrayList또한 sort를 사용할수있다.

(Collections의 sort 메소드는 Arrays의 sort메소드를 이용하긴한다.)

 

이 sort는 템플릿 메소드 패턴으로, 자신의 알고리즘이 동작하는데 필요한 CompareTo메소드를 서브클래스들에게 맡긴다.

sort의 API는 다음과 같다.

    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();
        Arrays.sort(a);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

내부적으로 Arrays의 sort를 사용하는게 보이는데, Arrays API에 있는 sort의 경우 굉장히 많은 오버로딩된 sort메소드가 있으므로, 생략한다. 

단지, Arrays의 sort는 O(NlogN)의 시간복잡도를 갖고있는 quick sort를 이용해 구현되어있으며, 이 과정에서 CompareTo의 반환값을 사용한다는것만 알고있으면된다.

 

sort는 Comparable인터페이스의 CompareTo 메소드를 사용해서 정렬을하는데, CompareTo의 리턴값이 -1이라면 뒤에있는것이 큰것, 1이라면 앞에있는것이 큰것, 0이라면 동일한것이다.

자바의 Comparable을 구현하는 API는 CompareTo메소드를 구현하고있어서, 우리는 별도의 구현없이 배열을 정렬할수있는것이다.

 

즉, 우리가 별도로만든 클래스를 정렬하기위해선 CompareTo 메소드를 구현해야한다는것이다.

 

준영이는 자신의 친구들에게 순위를 매기는 프로그램을 만들기로했다.

친구들 순위는 우선, 백준사이트의 문제를 푼 수로 결정된다. 이때, 푼 문제수가 같다면, solved.ac에서 얻은 경험치로 계산한다.

 

준영이를 도와 정렬 프로그램을 만들자.

 

입력은 다음과 같다.

첫번째 줄에 친구들의 수 N이 주어진다.

두번째 줄부터 차례대로 한줄에 친구의 이름, 백준에서 푼 문제수, solved에서 얻은 경험치 가 주어진다.

 

친구들을 오름차순 정렬한 값을 출력하자

 


구현

우리가 할 일은 CompareTo 메소드를 만드는것이다.

CompareTo 를 구현하는 Comparable의 소스코드는 다음과 같다.

public interface Comparable<T> {
    
    public int compareTo(T o);

}

int형을 반환하는 compareTo메소드가 있는것이 보이고, 비교를 어떠한 파라미터로도 할수있도록 제네릭타입을 사용한것이 보인다. 이에 맞춰서 친구들을 구현하도록 하자.

 

우선, 친구의 정보와 행동을 담을 클래스를 만들고 친구들이 비교 가능하도록 만든다.

public class Friends implements Comparable<Friends>{}

Comparable인터페이스를 구현하고, 제네릭에 Friends를 넣었다. (친구가 가지고있는 정보로 비교할것이므로..)

 

내부 내용을 구현하자. 우선, 입력받는 부분이다. 

친구들은 자신이 생성될때, 이름, 푼 문제수 경험치를 입력받는다.

    public Friends(){
        input(); // 친구들을 만들때 정보를 입력받는다.
    }
    
    private void input(){
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String info = br.readLine();
            String[] o = info.split(" ");
            this.name = o[0];
            this.solvedProb = Integer.parseInt(o[1]);
            this.exp = Double.parseDouble(o[2]);
        }catch(IOException IOE){
            System.exit(1);
        }
    }

 

다음은 제일 중요한 compareTo 메소드의 구현이다.

    @Override
    public int compareTo(Friends F){
        if(this.solvedProb > F.getSolvedProb()) return 1;
        if(this.solvedProb < F.getSolvedProb()) return -1;
        if(this.solvedProb == F.getSolvedProb()){
            if(this.exp > F.getExp()) return 1;
            else if(this.exp < F.getExp()) return -1;
        }
        return 0;
    }

(@Override는 필수는아니다.)

푼 문제수 -> 얻은 경험치 순서으로 봐주며 return 하는것을 볼수있다.

 

입 출력

4

A 1 1.0

B 2 1.0

C 2 3.1

D 1 0.9

D 1 0.9

A 1 1.0

B 2 1.0

C 2 3.1


전체 소스코드

https://github.com/devxb/DesignPatterns/tree/main/DesignPatterns/prob7_Friends

 

devxb/DesignPatterns

디자인 패턴 🤔. Contribute to devxb/DesignPatterns development by creating an account on GitHub.

github.com