티스토리 뷰

객체지향 설계의 3가지 관점

  • 아래 3가지 관점은 순서가 아닌 동일한 클래스를 3가지 다른 방향에서 바라보는 것을 의미

개념 관점 설계

  • 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현
  • 실제 도메인의 규칙과 제약을 최대한 유사하게 반영하는것이 핵심

명세 관점 설계

  • 실제 소프트웨어 안에서 살아 숨쉬는 객체들의 책임에 초점을 맞춰 설계
  • 인터페이스와 구현을 분리하는 것은 훌륭한 객체지향 설계를 낳는 가장 기본적인 원칙

구현 관점 설계

  • 객체들이 책임을 수행하는데 필요한 동작을 코드로 작성하는 것

실전 - 커피 전문점

커피 전문점

  • 커피 전문점이라는 도메인은 손님, 메뉴 항목, 메뉴판, 바리스타, 커피 객체로 구성된 작은 세상

도메인 모델

  • 소프트웨어가 대상으로 하는 영역인 도메인을 단순화해서 표현한 모델을 도메인 모델이라고 함
  • 어떤 타입(클래스)가 도메인을 구성하고 타입들 사이에 어떤 관계가 존재하는지 파악하기위한 용도

  • 메뉴판과 메뉴항목은 하나의 단위로 움직임
  • 메뉴판과 메뉴 항목은 합성 관계 표현 (최대 4개의 항목을 가짐)

  • 손님은 메뉴판을 알아야 커피를 선택할 수 있으나 메뉴판은 손님의 일부가 아니므로 연관 관계로 표현

  • 바리스타는 커피를 제조해야 하므로 커피를 알고 있어야함
  • 커피는 바리스타의 일부가 아니므로 연관관계로 표현

협력(메시지) 설계

  • 협력을 설계할때 메시지를 먼저 선택하고 후에 메시지를 수신하기에 적절한 객체를 선택해야함
  • 메시지를 먼저 선택시 수신할 객체에 대한 정보를 알수 없기 때문에 캡슐화를 지킬수 있음

  • 첫번째 메시지는 ‘커피를 주문하라’로 시작
  • 괄호 안은 메시지에 담아 전달될 부가적인 정보 인자

  • ‘커피를 주문하라’메시지를 수신할 객체로는 손님을 선택
  • 손님 객체는 커피를 주문할 책임 할당받음

  • 손님은 메뉴 항목에 대해 알지 못하니 메뉴 항목을 찾아줄 대상을 찾는다
  • ‘메뉴 항목을 찾아라’ 메시지가 새로 등장함

  • 메뉴판 객체가 메뉴를 포함하고 있으므로 메뉴판이 ‘메뉴 항목을 찾아라’ 메시지를 수신

  • 손님은 메뉴 항목을 알게되었으니 커피 제조를 요청할 객체를 찾는다

  • 바리스타는 커피를 제조하는데 필요한 정보를 알고있으므로 바리스타가 ‘커피를 제조하라’메시지를 수신

인터페이스 정리

  • 위에서 정리된 메시지를 가지고 인터페이스를 만든다
  • 각 객체를 협력에라는 문맥에서 떼어내서 수신하는 메시지만 추려내면 객체의 인터페이스가 됨

class Customer {
    public void order(String menuName) {}
}

---

class MenuItem {

}

---

public class Menu {
    public MenuItem choose(String menuName) {
        return null;
    }
}

---

class Barista {
    public Coffee makeCoffee(MenuItem menuItem) {
        return null;
    }
}

---

class Coffee {

}

코드작성

  • 위의 협력 관계를 참고하여 코드를 작성
  • 설게는 간단히 끝내고 최대한 빨리 구현에 들어가야함
  • 설계가 제대로 그려지지 않는다면 실제 코드를 작성해가면서 협력의 전체적인 밑그림을 그려본다
class Customer {
    public Coffee order(String menuName, Menu menu, Barista barista) {
        MenuItem choose = menu.choose(menuName);
        return barista.makeCoffee(choose);
    }
}

---

public class Menu {
    private final List<MenuItem> menuItems;

    public Menu(List<MenuItem> menuItems) {
        this.menuItems = menuItems;
    }

    public MenuItem choose(String menuName) {
        for (MenuItem menuItem : this.menuItems) {
            if (menuItem.getName().equals(menuName)) {
                return menuItem;
            }
        }

        return null;
    }

---

class MenuItem {
    private final String name;
    private final int price;

    public MenuItem(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public int cost() { return price; }
    public String getName() { return name; }
}

---

class Coffee {
    private final String name;
    private final int price;

    public Coffee(MenuItem menuItem) {
        this.name = menuItem.getName();
        this.price = menuItem.cost();
    }

    public void drink() {
        System.out.println("drink " + this.name + " coffee");
    }
}

---

class Barista {
    public Coffee makeCoffee(MenuItem menuItem) {
        return new Coffee(menuItem);
    }
}

도메인 개념을 참조하는 이유

  • 어떤 메시지가 있을때 수신할 객체를 선택할때 도메인 개념중에 가장 적절한 것을 선택하는것
  • 도메인지식을 기반으로 코드의 구조와 의미를 쉽게 유추가능
인터페이스와 구현을 분리하라! (캡슐화)

'독서 > 객체지향의 사실과 오해' 카테고리의 다른 글

chapter6. 객체지도  (1) 2023.12.22
chapter5. 책임과 메시지  (1) 2023.12.22
chapter4. 역할, 책임, 협력  (1) 2023.12.22
chapter3. 타입과 추상화  (0) 2023.12.22
chapter2. 이상한 나라의 객체  (0) 2023.12.22
댓글