GO SIWOO!

[객체지향의 사실과 오해] 7장 - 함께 모으기 본문

Develop/객체지향의 사실과 오해

[객체지향의 사실과 오해] 7장 - 함께 모으기

gosiwoo 2023. 8. 14. 16:09
 

[객체지향의 사실과 오해] 6장 - 객체 지도

[객체지향의 사실과 오해] 5장 - 책임과 메시지 [객체지향의 사실과 오해] 4장 - 역할, 책임, 협력 [객체지향의 사실과 오해] 3장 - 타입과 추상화 [객체지향의 사실과 오해] 2장 - 이상한 나라의 객

gosiwoo.tistory.com

📌이 장에서는...

6장까지의 내용은 객체지향 세계를 만들기 위해서 현실세계의 은유를 통해 만든다는 기본적인 개념과 함께 역할, 협력, 책임을 기반으로 객체를 나누고 메시지를 통해 객체는 협력을 해야 하며 외부 인터페이스와 내부 인터페이스(구현)를 명확히 구분해 유연한 객체지향 세계를 만들 수 있다고 하였다.

1장에서 사용한 커피 전문점의 예를 활용해 어떻게 객체지향 세계를 만들어야 할지 알려주는 장이다.


1. 마틴파울러의 객체지향 설계 3가지 관점

마틴 파울러는 개념 관점(Conceptual Perspective), 명세 관점(Specification Perspective), 구현 관점(Implementation Perspective)의 3가지 관점으로 객체지향 소프트웨어 설계 방향을 제시한다.

개념 관점(Conceptual Perspective)

사용자들이 관심을 가지고 있는 분야나 주제에 관한 도메인의 관점으로 개념과 개념들 사이의 관계를 표현한다. 사용자의 관점으로 실제 도메인의 규칙과 제약을 최대한 유사하게 반영하는 것이 핵심이다.

명세 관점(Specification Perspective)

명세 관점에서는 개념 관점의 사용자의 관심에서 개발자의 영역인 소프트웨어로 초점이 변경된다. 소프트웨어 안에 있는 객체에 초점이 맞춰지며 객체 간의 메시지, 즉 외부 인터페이스에 관심을 지니며 이는 객체가 협력에서 '무엇(what)'을 할 수 있을지에 초점을 맞추어 설계를 하는 것이 중요하다.

인터페이스와 구현의 명확한 분리를 위해 최대한으로 구현 부분을 제거함으로써 유연한 객체지향 세계를 만들 수 있게 해야 한다.

구현 관점(Implementation Perspective)

명세 관점에서는 외부 인터페이스에 초점을 맞추었다면 구현 관점에서는 개발자들이 직접 마주하는 실제 작동 코드에 중점이 맞춰져 있다. 각 객체가 자신이 맡은 책임을 어떻게 수행을 하는지 동작하는 코드를 통해 구현을 해야 한다. 객체가 책임을 '어떻게(how)' 처리를 하는지 초점을 맞추며 인터페이스를 구현하며 속성, 메서드를 작성한다.

 

2. 커피 전문점을 통해 보는 3가지 관점

손님이 커피 주문을 진행하는 세계를 앞서 설명한 3가지 관점에서 어떻게 객체지향 설계를 하는지 살펴본다.

개념 관점(Conceptual Perspective)

커피 전문점의 객체 세상

사용자 관점에서 바라보면 손님이 커피를 메뉴판을 통해 정하고 바리스타에게 커피를 주문해 바리스타는 커피를 만들어 내는 커피 전문점을 도메인 관점으로 위와 같이 표현할 수 있다.

각 개념들 사이에서는 관계가 설정되어 있으며 손님 객체가 메뉴판 객체와 바리스타와 객체와의 관계를 갖고 있으며 손님은 커피를 주문하는데 커피 객체와 관계를 맺을 필요는 없다. 단지 손님은 메뉴판 객체로부터 커피 메뉴를 가져올 수 있으면 그만이다.

 

아래는 위와 같은 커피 전문점의 관계를 바탕으로 클래스를 도출하면 개념 관점에서 얻을 수 있는 관계 중심의 그래프는 다음과 같다고 할 수 있다. 여기서 마름모는 Composition으로 UML 클래스 다이어 그램에서 사용하는 포함 관계의 기호이다.

커피 전문점의 관계 중심의 클래스 도출

명세 관점(Specification Perspective)

 

커피 전문점에서 객체 간의 메시지를 추출해 인터페이스를 구성해 보았다. 각 메시지는 외부 인터페이스로서 상태, 메서드와 같은 구현 부분은 전혀 고려하지 않고 객체가 무엇(what)을 해야 하는지에 관해서만 고려하고 있음을 알 수 있다.

인터페이스 기반의 설계를 통해 객체의 유연성(flexibility), 재사용성(reusability)을 챙길 수 있을 것이다.

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

class MenuItem {
}

class Menu {
	public menuItem choose(String menu) {}
}

class Barista {
	public Coffee makeCoffee(MenuItem menuItem) {}
}

class Coffee {
	public Coffee(MenuItem menuItem) {}
}

추출한 인터페이스를 통해 JAVA의 클래스 방식으로 인터페이스를 작성해 보았다. 보다시피 인터페이스만 작성했을 뿐 메서드의 작동이나 상태 등은 전혀 표현하지 않은 상태이다.

구현 관점(Implementation Perspective)

커피 전문점의 구현 최종 클래스

앞서 추출한 인터페이스의 구현 부분을 채우는 과정이다. 인터페이스를 바탕으로 메서드와 필드를 채운 클래스가 나오게 되었다. 이는 개발자가 최종적으로 시스템을 만들기 위해 작성하는 최종 결과물로 모든 구현이 끝난 상태이다. 이는 객체가 책임을 수행하는 어떻게(how) 방식을 나타낸다.

 

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

JAVA에서 클래스의 구현 코드는 위와 같은 형태를 띨 것이다.

 

3. 3가지 관점의 필요성

굳이 위의 3가지 복잡한 관점에서의 설계를 통해 코드를 구현해야 하는 이유가 무엇일까?

 

인터페이스와 구현을 분리함으로써 변동되는 요구사항에 대처할 수 있는 세계를 만들어야 한다.

클라이언트는 변덕이 심하고 사용하는 기술들은 매일 발전한다. 재사용이 가능하고 유지보수가 쉬운 코드를 만들기 위해 인터페이스와 구현을 명확히 분리함으로써 우리가 작성한 코드를 감추자(캡슐화). 분리되지 않고 흐릿한 구분이 되어있는 설계는 언젠가 망가지므로 앞서 설명한 3가지 관점에서 클래스를 바라보며 시스템을 설계하자.


📌책을 마무리하며

Spring Framework를 통해 개발 공부를 진행하며 설계에 대해 많은 고민이 있었다. 패키지를 도메인 별로 나누어야 할지 계층별로 나누어야 하는지에 대한 사소한 고민부터 Entity 클래스의 책임을 어디까지 부여해 비즈니스 로직을 어디에 둘지가 고민이었다.

 

이 고민은 도메인 모델 패턴과 트랜잭션 스크립트 패턴의 차이라는 것을 알게 되었고 객체지향 설계를 지향하기 위해서는 객체를 책임을 수행할 하나의 사람으로 본다면 도메인 모델 패턴을 지향하는 것이 맞다고 본다. 

이에 대해서 찾아보니 역시 도메인 모델은 이 책에서 설명한 바와 같이 객체들 간의 관계와 메시지를 기반으로 꼼꼼한 설계를 기반으로 시작되어야 하며 이는 높은 재사용성과 확정성을 이끌어낼 수 있다고 한다.

 

막막한 설계에 대한 고민 해결방향을 찾을 수 있는 책이었다.