본문 바로가기
테크스토리

Interface & Abstract Class 첼린지 후기

by 쏘세지입술 2022. 10. 21.
반응형

얼마만에 포스팅인지 하핫... 그동안 여행도 다니고 우아한 테크코스 지원한다고 자소서 쓰다보니 시간이 없었다(는 핑계..)

오늘 포스팅 할 문제만 3-4일 걸려서 풀었던거 같다! 원래는 interface와 abstract class가 메인이였으나 나중에는 코드를 이해하려고 쏟은 시간이 대부분이였다능... 암튼 시작한다!

 


1. ListItem

 

package danHeeYoung;

public abstract class ListItem {
	
	protected ListItem rightLink;
	protected ListItem leftLink;
	protected Object value;
	
	public ListItem(Object obj) {
		value = obj;
	}
	
	abstract ListItem next();
	abstract ListItem setNext(ListItem listItem);
	abstract ListItem previous();
	abstract ListItem setPrevious(ListItem listItem);
    abstract int compareTo(ListItem listItem);
	
	public Object getValue() {
		return this.value;
	}
	
	public void setValue(Object obj) {
		this.value = obj;
	}
}

추상 클래스이다! 링크리스트이다보니 왼쪽, 오른쪽 객체가 하니씩 있고 어떤 값을 가지고 있는 value 또한 있다. 클래스를 추상으로 declare하려면 최소 하나에 메소드는 추상으로 지정해야한다! 이 클래스에는 총 5개의 추상 메소드가 있다!

 


2. Node

package danHeeYoung;

public class Node extends ListItem{
	
	public Node(Object obj) {
		super(obj);
	}

	@Override
	ListItem next() {
		return this.rightLink;
	}

	@Override
	ListItem setNext(ListItem listItem) {
		this.rightLink = listItem;
		return this.rightLink;
	}

	@Override
	ListItem previous() {
		return this.leftLink;
	}

	@Override
	ListItem setPrevious(ListItem listItem) {
		this.leftLink = listItem;
		return leftLink;
	}

	@Override
	int compareTo(ListItem listItem) {
		if(listItem!=null) {
			return ((String)super.getValue()).compareTo( (String)listItem.getValue());	
		}
		return -1;
	}
	
	
}

위에 추상 클래스인 ListItem을 extend한다. 링크리스트이기에 왼쪽, 오른쪽 노드를 지정하고 옮길수 있는 추상 메소드 들을 이 클래스에서 정의한다! 또한 compareTo 메소드  같은 경우 ListItem 에 value 변수가 object로 지정이 되어있기 때문에 (String)으로 케스트 해주고 비교한다. (이럴거면 애초에 String으로 설정 했어도 되지 않나? 싶은 생각이 들지만 문제 지침에 써있었으니까 봐준다..). 

* 이 compareTo 메소드 이해하는게 아직 조금 부족했는지 이 메소드 사용할때 조금 헷갈렸다. 

int result = current.compareTo(newItem);

요런 코드가 있다면 current라는 변수와 newItem이라는 변수를 비교하는건데 앞에 나오는 current가 더 크다면 (current > newItem) 리턴되는 result는 > 0 이고, 뒤에 나오는 newItem이 더 크다면 (current < newItem), result < 0 이된다! 만약 값이 같다면 0이 리턴된다!

 


 

3.NodeList 

package danHeeYoung;

public interface NodeList {
	
	ListItem getRoot();
	boolean addItem(ListItem listItem);
	boolean removeItem(ListItem listItem);
	void traverse(ListItem root);
	
}

첫 인터페이스이다! 4개의 static 메소드가 있다. 

인터페이스에 대해서 조금더 알아보니 3개의 메소드가 존재한다고 한다. (static, default, private) 

아래 링크에 굉장히 상세하게 나와있다!

https://velog.io/@foeverna/Java-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EC%9A%94%EC%86%8C%EB%93%A4

 

[Java] 인터페이스 - 인터페이스의 요소들

인터페이스의 요소 상수 : 선언된 모든 변수는 상수로 처리됩니다. 메서드 : 인터페이스에 모든 메서드는 추상 메서드입니다. 디폴트 메서드 : 구현코드가 없는 인터페이스에서 공통적으로 구현

velog.io

 

참고로! java8부터는 인터페이스 안에서 default라는 메소드를 사용하면 정의뿐만이아니라 구현또한 가능하다고 한다! 그리고 이 default 메소드는 인터페이스를 구현하는 클래스에 자동적으로 상속된다!

 


4. MyLinkedList

package danHeeYoung;

public class MyLinkedList implements NodeList{
	
	private ListItem root;
	
	public MyLinkedList(ListItem listItem) {
		root = listItem;
	}

	@Override
	public ListItem getRoot() {
		return this.root;
	}

	@Override
	public boolean addItem(ListItem newItem) {
		if(root==null) {
//			root.setNext(newItem);
			 this.root = newItem;
			return true;
		}
		
		ListItem current = root;
		
		while(true) {
			
			int result = current.compareTo(newItem); // compare the root with the given newItem
			
			if(result<0) { 							// if newItem is greater than current
				if(current.next()!=null) {
					current = current.next();
				} else {
					newItem.setPrevious(current).setNext(newItem);
					return true;
				}
			} else if(result>0) {					// if current is greater than the newItem
				if(current.previous()!=null) {
					current.previous().setNext(newItem).setPrevious(current.previous());
					newItem.setNext(current).setPrevious(newItem);
//					newItem.setNext(current).setPrevious(newItem);
//					newItem.setPrevious(current.previous()).setNext(newItem);
					return true;
				} else {
					current.setPrevious(newItem).setNext(current);
					this.root = newItem;
					return true;
				}
			} else {
				System.out.println("Line 43");
				return false;
			}
		}
	}

	@Override
	public boolean removeItem(ListItem newItem) {
		ListItem current = root;
		
		while(current!=null) {
			int comparision = current.compareTo(newItem);
			if(comparision==0) {									// found the item to delete
				if(current.equals(newItem)) {						// newItem to be deleted is the root
					root = current.next();
				} else {											// item to be deleted is not root
					current.previous().setNext(current.next());
					if(current.next()!=null) {							// next item exists!
						current.next().setPrevious(current.previous());
					}
				}
				return true;
			} else if(comparision<0) {								// current is greater than item to be deleted, so move to the next item
				current = current.next();
			} else {												// item to delete is greater
				return false;
			}
		}
		return false;
	}

	@Override
	public void traverse(ListItem root) {
		if(root==null) {
			System.out.println("The list is empty");
		} else {
			while(root.next()!=null) {
				System.out.println(root.value);
				root = root.next();
			}
		}

		
	}
	
	
	
}

가장 힘들었던 클래스이다! 일단 NodeList를 상속하니 그 안에 있던 메소드들을 이 클래스에서 정의한다. 특히 addItem 메소드가 힘들었는데 이번 첼린지를 하면서 뼈저리게 느꼈던 것중 하나가 코드가 길어지고 생각해야할게 많은 코드라면 중간중간에 꼭 // 를 사용하여 메모해야할 필요가 있다는 것이다! 링크리스트의 개념을 통해 구현하는것이다 보니 하나하나 종이에 그려가면서 코드를 짰는데 코드가 점점 길어지다 보니 전에 코드가 무슨 의미였고 왜 이렇게 구현하였는지 헷갈리고 잊어버리기도 한다. 그래서 애초에 각각에 코드에 설명을 붙이면 다시 돌아가서 체크할때 굉장히 편하다는걸 느꼈다. 특히 compareTo 메소드 쓸때... 메모 안하고 그냥 머리로만 하려고 하니까 머리 깨질뻔 했다. 

 


5. Main

 

간단히 시험해 보았다.

package danHeeYoung;

public class Main {

	public static void main(String[] args) {
		MyLinkedList list = new MyLinkedList(null);
		
		list.traverse(list.getRoot());
		
		String data = "서울 대전 광주 부산 천안 충주 파주 의정부 연천 포천 울산";
		String[] dataArr = data.split(" ");
		
		for(String s: dataArr) {
			list.addItem(new Node(s));
		}
		
		list.traverse(list.getRoot());
		list.removeItem(new Node("의정부"));
		list.removeItem(new Node("연천"));
		System.out.println();
		list.traverse(list.getRoot());
		list.addItem(new Node("뉴욕"));
		list.addItem(new Node("시에틀"));
		System.out.println();
		list.traverse(list.getRoot());

	}

}
더보기

The list is empty

광주

대전

부산

서울

연천

울산

의정부

천안

충주

파주

 

광주

대전

부산

서울

울산

천안

충주

파주

 

광주

뉴욕

대전

부산

서울

시에틀

울산

천안

충주

파주

결과는 이렇게 나온다~! 

 


느낀점!

이번 첼린지를 하면서 중간중간 설명을 붙이는게 왜 중요한지 알게되었다. 생각에 흐름을 놓치지 않게 도와주고 혹시라도 흐름을 놓쳐서 전 코드를 체크해야할때도 굉장이 용이하다는것을 느꼈다.

그리고 오늘과 같이 자료구조와 같은 생각을 많이 해야하고 각각에 절차를 생각해야할때는 가만히 앉아서 머리 싸매고 있는 것보다는 종이에 그려가면서 구현하는게 훨씬 도움이 됬다. 그래서 드는 생각이 조그만 화이트보드를 구매하면 좋을거같다는 생각을 했다. 화이트보드는 쓰고 지울수있으니 종이 낭비도 안하니까 말이다. 

굉장히 오랫만에 한 블로그 포스팅인데 앞으로도 꾸준히 달려보자 아자아자!!

반응형

댓글