티스토리 뷰

이번에는 좀더 그럴듯한 제너릭 예제를 만들어 보자. 앞에서 Manageable과 Manager 클래스를 살펴보았다. Manageable 인터페이스는 Manager를 만들 수 있는 공통된 메소드의 정의를 제공한다.

이전 포스트에서 살펴본 Manager는 Manageable을 다루기 위한 메소드(입력, 출력, 검색 등)를 제공하는 클래스다. 그러면 이것을 Manageable을 상속한 어떠한 클래스에 대해서든 관리자로 쓸 수 있다. 

Manager studentMgr = new Manager();
studentMgr.readAll("student.txt");
studentMgr.printAll();
Student st = (Student)studentMgr.find("lee");

여기서 제너릭에 관해 처음에 얘기했던 문제, 즉 다운캐스팅을 해야 한다는 문제가 생긴다. Student를 관리하는 클래스이지만 코드 상으로는 이 클래스는 Manageable을 가지고 있을 뿐이다. 그러므로 읽고 출력하고 검색하고 잘 하지만 코드에서 Student가 필요할 때는 다운캐스팅을 해서 써야 한다.

제너릭을 사용하면 이러한 문제가 해결된다. Student 타입의 매니저를 따로 만들 수 있다.

Manager<Student> studentMgr = new Manager<>();
studentMgr.readAll("student.txt");
studentMgr.printAll();
Student st = studentMgr.find("lee");

제너릭 매니저는 다음과 같이 정의될 것이다. 이 코드는 앞의 포스트에서 Manageable이던 자리에 T를 바꾸어 넣은 것을 볼 수 있다.

class Manager<T extends Manageable> { ArrayList<T> mList = new ArrayList<>(); Scanner scan = new Scanner(System.in); void readAll(Scanner scan, Factory<T> fac) {

System.out.print("개수 : "); int n = scan.nextInt(); T m = null; for (int i = 0; i < n; i++) { m = fac.create(); // *** 컴파일 오류 m.read(scan); mList.add(b); } } void printAll() { for (T m : mList) m.print(); } T find(String kwd) { for (T m : mList) if (m.compare(kwd)) return m; return null; } }

첫 줄의 부분은 이 제너릭 클래스가 사용할 타입 T가 제약조건을 가진 타입(Bounded Type Parameter)임을 나타낸다. 

class Manager<T extends Manageable> { 

T 자리에 올 수 있는 타입은 Manageable을 implements한 타입만 가능하다는 뜻이다. 이러한 제약조건이 있기 때문에 위의 코드에서 T 변수에 대해 read, print, compare 메소드를 사용할 수 있었다. 그러면 studentMgr.find("lee")의 반환값은 Student 객체가 될 것이다. 

Manager<Student> studentMgr = new Manager<>();

또 한 가지 이 studentMgr 객체는 Student 타입의 요소만 가지게 된다. 즉 그 내부의 mList도 ArrayList<Student>로 생성되고 모든 요소 객체는 Student 타입일 것이므로 Manageable을 상속한 다른 타입의 객체가 섞여있을 위험은 원천 차단된다. (컴파일러에 의해서...)

다음으로 Sellable 인터페이스를 이용한 Store 클래스를 생각해 보자. Store 클래스는 Manager가 가진 기능 이외에 팔고 사는 것, 고객 관리, 장바구니 관리, 결재 기능 등을 가질 수 있다. 이러한 것을 Store 클래스로 만들고 Manager를 상속하게 하고 싶다. Store가 필요로 하는 요소 클래스의 기능은 Sellable 인터페이스로 보장될 것이다. (각 상품이 가격정보를 가지고 재고, 판매, 상품정보제공 등의 기능을 가질 수 있다.)

앞에서 살펴보았듯이 Sellable은 Manageable을 extends할 수 있다. 즉 기본적인 읽고 쓰고 비교하는 기능을 물려받고 추가로 판매될 수 있는 상품이 가져야 할 메소드들을 선언하는 것이다. (구현은 그것을 구현한 구체 클래스에서 할 것이다.) 그럼 다음과 같이 Store 클래스를 제너릭으로 선언할 수 있다. 여기서 T는 Sellable을 구현한 클래스인데, 그럼 당연히 Manageable도 구현했을 것이므로 Manager의 제너릭 타입 파라매터가 될 수 있다. 그러므로 Store<T>가 Manager<T>를 상속할 수 있고 그 타입 T는 Manager에서도 그대로 쓰일 수 있다.

class Store<T extends Sellable> extends Manager<T> {

이 클래스는 상품 검색이나 상품 판매 기능을 다음과 같이 제공할 수 있다. 여기서 노란색 메소드들은 T 클래스가 제공해야 하는 인터페이스에 의해 보장된다. 또한 readAll, printAll 등의 메소드는 Manager에서 물려받아 쓸 수 있다.

class Store<T extends Sellable> extends Manager<T> { void open(String filename) { readAll(filename); printAll(filename); System.out.println("*** Store is up! ***");

} void search(String kwd) { for (T item : mList) { if (item.compare(kwd)) item.showInfo(); } } boolean request(Customer c, T item, int n) { if (!item.checkStock(n)) return false; item.sell(n); c.addItem(item, n); } }



댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함