객체지향의 사실과 오해 스터디

[객체지향의 사실과 오해] Chapter 7

changha. 2024. 1. 20. 00:36

함께 모으기 

객체지향 세 가지 상호 연관된 관점

  • 개념 관점
    • 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현함 
    • 실제 도메인의 규칙과 제약을 최대한 유사하게 반영하는 것이 핵심 
  • 명세 관점
    • 도메인 영역을 벗어나 소프트웨어로 초점이 옮겨짐 
    • 객체들의 책임에 초점을 맞춤
    • 객체가 협력을 위해 '무엇'을 할 수 있는가에 초점
  • 구현 관점
    • 실제 작업을 수행하는 코드와 연관됨 
    • 객체의 책임을 '어떻게' 수행할 것인가에 초점

개념 -> 명세 -> 구현 관점 순서대로 소프트웨어 개발이 아님!(x)

세 가지 다른 방향에서 바라보는 것을 의미함

동시에 세 가지 관점을 쉽게 식별할 수 있어야 함

 

다음 간단한 예시로 두가지 목표를 달성할 것

  1. 도메인 모델에서 시작해서 최종 코드까지의 구현 과정 간략히 
  2. 구현 클래스를 개념 관점, 명세 관점, 구현 관점에서 바라본다는 것이 무엇을 의미하는지 설명 

 

커피 전문점 도메인

커피 전문점이라는 세상 

객체지향적 관점에서 살펴보면,

손님은 메뉴판을 보고 바리스타에게 원하는 커피를 주문함 

손님, 메뉴판, 메뉴 항목, 바리스타, 커피 객체로 구성됨

 

객체들 간의 관계를 살펴보자

  • 손님은 메뉴판에서 주문할 커피를 선택할 수 있어야 함 
    • 손님과 메뉴판 사이의 관계 필요 
  • 손님은 바리스타에게 주문 해야 함 
    • 손님과 바리스타 사이의 관계 필요 
  • 바리스타는 자신의 커피와도 관계가 필요함 

도메인 모델

 

 

위 그림을 보면 

메뉴판과 메뉴사이는 합성 관계이다. 

그 외는 서로 알고 있어야 하는 경우, 즉 연관 관계 이다. 

 

이제 초점을 소프트웨어로 옮겨 보자 

협력을 설계해보자 

 

설계하고 구현하기

커피를 주문하기 위한 협력 찾기 

객체지향의 목표는 

훌륭한 협력을 설계하는 것

훌륭한 객체는 훌륭한 협력을 설계할 때만 얻을 수 있음 

-> 메시지가 객체를 선택하게 해야 함 

 

첫 번째 메시지 

'커피를 주문하라' 

이 메시지 책임은 손님 객체에게 어울림 

손님이 메시지 수행 도중에 스스로 할 수 없는 것이 무엇이 있을까?

메뉴 항목이다.

'메뉴 항목을 찾아라' 메시지 수신에 어울리는 객체는 무엇일까?

메뉴판이다.

 

이제 커피 제조 단계,

'커피를 제조하라'의 메시지 수신자는 바리스타가 어울린다.

'커피를 생성하라'의 메시지 수신자는 커피 객체이다.(?)-> 커피라는 객체가 생성메서드를 사용하면 되는것일까?

 

인터페이스 정리 

객체가 수신한 메시지가 객체의 인터페이스를 결정함

메시지가 객체를 선택했고, 선택된 객체는 메시지를 자신의 인터페이스로 받아들임

객체가 어떤 메시지 수신 -> 그 객체의 인터페이스 안에 메시지에 해당하는 오퍼레이션 존재 

 

오퍼레이션은 외부에서 접근 가능한 공용 인터페이스의 일부임 

class Customer {
	public void order(String menuName) {}
}
class MenuItem {
	
}
class Menu {
	public MenuItem choose(String name) {}
}
class Barista {
	public Coffee makeCoffee(MenuItem menuItem){}
}
class Coffee {
	public Coffee(MenuItem menuItem){}
}

 

구현하기

Customer입장에서 Menu에게 MenuItem을 도출하도록 해야 함 

이후 Barista에게 제조 요청해야 함 

class Customer {
	public void order(String menuName, Menu menu, Barista barista) {
    	MenuItem menuItem = menu.choose(menuName);
        Coffee coffee = barista.makeCoffee(menuItem);
    }
}

 

Menu는 아이템 목록을 알아야하고 찾을수 있어야 함 

class Menu {
	private List<MenuItem> items;
    
    public Menu(List<MenuItem> items) {
    	this.items = items;
    }
    
    public MenuItem choose(String name) {
    	for(MenuItem each : items){
        	if(each.getName().equals(name)){
            	return each;
            }
        }
        
        return null;
    }
}

이런 식으로 코드를 작성하면 된다.

Barista는 커피 제조 메서드가 필요하고 

Coffee는 이름과 가격이 필요하다 (생성자로 반환가능)

MenuItem은 이름과 가격을 알려주는 메서드가 필요하다.

최종 클래스 구조

 

코드의 세 가지 관점

 코드는 세 가지 관점을 모두 제공해야 한다.

먼저 개념관점

  • Customer, Menu, MenuItem, Barista, Coffee 
    • 모두 커피 전문점 도메인을 구성하는 중요한 개념과 관계를 반영함
  • 커피 제조과정 변경해야 한다면?
    • 커피 제조하는 사람인 바리스타에서 수정해야 함 

 

명세 관점

  • 클래스의 인터페이스를 바라봄 
  • 공용 인터페이스는 외부의 객체가 해당 객체에 접근할 수 있는 유일한 부분
    • 따라서 수정하기 어려움 
  • 구현과 관련된 세부사항이 드러나지 않도록 해야 함 

구현 관점 

  • 클래스의 메서드와 속성이 구현에 속함 
    • 클래스 내부의 비밀임 

 

세 가지 관점이 명확하게 드러날 수 있게 코드를 개선하라! 

 

 

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

어떤 메시지가 있을 때 그 메시지를 수신할 객체를 어떻게 선택하는가?

도메인 개념 중에서 가장 적절한 것을 선택

 

인터페이스와 구현을 분리하라 

 

명세 관점은 클래스의 안정적인 측면을 드러내야 함 

구현 관점은 클래스의 불안정한 측면을 드러내야 함 

 

명세 관점이 설계를 주도하게 되면 

설계의 품질이 향상 됨

 

클래스를 봤을 때 명세 관점과 구현 관점으로 나눠 볼 수 있어야 함