본문 바로가기
Java

Objects 시리즈_3장.책임, 역할, 협력

by Jordy-torvalds 2020. 4. 22.
반응형

객체 지향 패러다임의 관점에서 핵심은 역할(role), 책임(responsibility), 협력(collaboration) 이다.

객체 지향의 본질은 협력하는 객체들의 공동체를 창조하는 것이다.

객체들이 애플리케이션의 기능을 구현하기 위해 수행하는 상호작용을 협력이라고 한다.

객체가 협력에 참여하기 위해 수행하는 로직을 책임이라고 부른다.

객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 역할을 구성한다.


협력

협력이란 어떤 객체가 다른 객체에게 무엇인가를 요청하는 것이다. 한 객체는 어떤 것이 필요할 떄 다른 객체에게 전적으로 위임하거나 서로 협력한다. 즉, 두 객체가 상호작용을 통해 더 큰 책임을 수행하는 것이다. 객체 사이의 협력을 설계할 때는 객체를 서로 분리된 인스턴스가 아닌 협력하는 파트너로 인식해야 한다.

메세지 전송은 객체 사이의 협력을 위해 사용할 수 있는 유일한 커뮤니케이션 수단이다. 메서드를 수신한 객체는 메서드를 실행해 요청에 응답한다.

ex) 특정 클래스에서 List 인터페이스로 만들어진 a객체에 add란 메시지를 보내면 실제 서브 타입(subtype, 인터페이스를 상속한 클래스)인 ArrayList의 add 메소드 내 로직으로 처리한 후에 메세지에 대한 응답을 반환한다.

자율적인 객체란 자신의 상태를 직접 관리하고 스스로의 결정에 따라 행동하는 객체다.

결과적으로 객체를 자율적으로 만드는 가장 기본적인 방법을 내부 구현을 캡슐화하는 것이다.

객체가 참여하는 협력이 객체를 구성하는 행동과 상태 모두를 결정한다. 따라서 협력을 객체를 설계하는데 필요한 일종의 문맥(context)를 제공한다.

문맥(context)
서로 이어져 있는 문장의 앞, 뒤 관계


책임

책임이란 협력에 참여하기 위해 객체가 수행하는 행동을 말한다.

크레이그 라만은 객체의 책임을 크게 '하는 것(doing)', '아는 것(knowing)' 의 두가지 범주로 나누어 세분화 했다,

  • 하는 것
    • 객체를 생성하거나 계산을 수행하는 등의 스스로 하는 것
    • 다른 객체의 행동을 시작시키는 것
    • 다른 개게의 활동을 제어하고 조절하는 것
  • 아는 것
    • 사적인 정보에 관해 아는 것
    • 관련된 객체에 관해 아는 것
    • 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것

객체는 자신이 맡은 책임을 수행하는데 필요한 정보를 알고 있을 책임이 있다. 또한 객체는 자신이 할수 없는 작업을 도와줄 객체를 알고 있을 책임이 있다.

크레이그 라만은 객체지향 개발에서 가장 중요한 능력은 '책임을 능숙하게 소프트웨어 객체에 할당하는 것' 이라고 했다.

책임 할당

자율적인 객체를 만드는 가장 기본적인 방법은 책임을 수행하는데 필요한 정보를 가장 자라 알고 있는 정문가에게 그 책임을 할당하는 것이다. 이를 책임 할당을 INFORAMTION EXPERT(정보 전문가)패턴 이라고 부른다.

객체들 역시 협력에 필요한 지식과 방법을 가장 잘 알고 있는 객체에게 도움을 요청한다.

정보 전문가에게 책임을 할당하는 것만으로 상태와 행동을 함께 가지는 자율적인 객체를 만들 가능성이 높아지기 때문이다.

책임 주도 설계

책임을 갖고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방식을 책임 주도 설계(Responsibility-Driven Design, RDD) 라 한다.

  • 과정
    • 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다. | 파악
    • 시스템 책임을 더 작은 책임으로 분할한다. | 분할
    • 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다. | 할당
    • 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다 | 탐색
    • 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다. | 협력

책임을 할당할 때 고려해야 하는 두 가지 요소

  • 메세지가 객체를 결정
  • 행동이 상태를 결정

메세지가 객체를 결정한다.

메세지가 객체를 선택해야 하는 두 가지 중요한 이유는 다음과 같다.

  1. 객체가 최소한의 인터페이스를 가질 수 있게 된다.
    필요한 메세지가 식별될 때 까지 객체의 퍼블릭 인터페이스에 어떤 것도 추가하지 않기 때문.
  2. 객체를 추상적인 인터페이스를 가질 수 있게 된다.
    객체의 인터페이스는 무엇(what)을 하는 지는 표현해야 하지만 어떻게(how) 수행하는지를 노출해서는 안된다.

행동이 상태를 결정한다.

객체협력에 필요한 행동을 제공해야 한다.

객체를 객체답게 만드는 것은 객체의 상태가 아니라 객체가 다른 객체에게 제공하는 행동이다.

객체가 협력에 적합하는지를 결정하는 것은 그 객체의 상태가 아니라 행동이다.

얼마나 적절한 객체를 창조했느냐는 얼마나 적절한 책임을 할당했느냐에 달려있고, 책임이 얼마나 적절한지는 협력에 얼마나 적절한 가에 달려 있다.

객체가 행동이 아니라 상태에 초점을 둘 경우 객체의 내부 구현이 객체의 퍼블릭 인터페이스에 노출되도록 만들기 때문에 캡슐화를 저해한다.

객체의 내부 구현에 초점을 맞춘 설계 방식은 데이터-주도 설계(Data-Driven Design)이라고 부르기도 한다.


역할

역할은 객체가 어떤 특정한 협력 안에서 수행하는 책임의 집합을 역할이라고 부른다.

책임을 할당하는 과정은 다음과 같다.

  1. 특정한 메세지를 처리할 수 있는 역할이 무엇인가를 찾는 것
  2. 역할을 수행할 특정한 객체를 선택하는 것.

유연하고 재사용 가능한 협력

역할이 중요한 이유는 역할을 통해 유연하고 재사용 가능한 협력을 얻을 수 있기 때문이다.

메세지를 처리할 수 있는 구체적인 객체가 여러 개일 경우 그 객체들은 동일한 역할을 수행 한다고 볼 수 있다.

역할은 다른 것으로 교체할 수 있는 책임의 집합이다. 그래서 특정한 협력에 있어 특정한 역할이 필요할 때 해당 역할을 수행할 수 있는 객체는 무엇이든 대체할 수 있다.

역할은 여러 종류의 구체적인 객체를 포괄하는 추상화이다. 그래서 역할에 이름을 부여할 때는 여러 구체적인 객체를 포괄할 수 있는 추상적인 이름을 부여해야 한다.

역할을 이용하면 불필요한 중복 코드를 제거할 수 있고 협력 또한 더 유연해진다.

역할의 구현

역할을 구현하는 가장 일반적인 방법은 추상 클래스인터페이스를 사용하는 것이다.

추상 클래스책임의 일부를 구현해 놓은 것이고, 인터페이스구현 없이 책임의 집합만을 나열해 놓았다는 차이가 있지만 협력의 관점에서는 둘 모두 역할을 정의할 수 있는 구현 방법이라는 공통점을 공유한다.

(+) 최근에는 인터페이스 자체에서 정적인 메소드를 구현할 수 있어 이전보다 더욱 모호해졌다.

객체 대 역할

객체에 관해 생각을 할 때 '이 객체가 무슨 역할을 수행해야 하는가?' 라고 자문하는 것이 도움이 된다. 이 질문은 객체가 어떤 형태를 띠어야 하는지, 그리고 어떤 동작을 수행해야 하는지에 집중할 수 있게 도와준다. 지금까지 객체와 역할에 대해 막연하게 이야기를 했는데, 둘의 진짜 차이는 무엇일까? 만약 동일한 종류의 객체가 하나의 역할을 항상 수행한다면 둘을 동일한 것이다. 하지만 어떤 협력에서 하나 이상의 객체가 동일한 책임을 수행할 수 있다면 역할은 서로 다른 방법으로 실행할 수 있는 책임의 집합이 된다. 역할이란 프로그램이 실행될 댸 소프트웨어 기계 장치에서 적절한 객체로 메워 넣을 수 있는 하나의 슬롯으로 생각할 수 있다. 배우가 극중에서 믿을 수 있는 배역을 맡아서 하려는 것처럼 객체는 의미 있는 역할을 정의하는 책임을 통해 애플리케이션의 기능을 담당하게 된다.

위는 레베카 워프스블록이 한 말이다.

정리하자면, 협력에 참여하는 후보가 여러 종류의 객체에 의해 수행될 필요가 있다는 그 후보는 역할이 되지만 단지 한 종류의 객체만이 협력이 참여할 필요가 있다면 후보는 객체가 된다.

다시 말해, 협력에 적합한 책임을 수행하는 대상이 한 종류라면 간단하게 객체로 간주하고, 여러 종류위 객체들이 참여할 수 있다면 역할이라고 부르면 된다.

중요한 것은 객체와 역할을 구분 짓는 것은 크게 중요하지 않다는 것이다.

역할과 추상화

앞서 2장에서 추상화를 이용한 설계가 가질 수 있는 두 가지 장점을 설명했고, 정리하자면 다음과 같다.

  1. 추상화 계층 만을 이용하면 중요한 정책을 상위 수준에서 단순화할 수 있다.
  2. 설계가 좀 더 유연해진다.

첫번째 장점을 예로 들자면 다음과 같다.

영화 요금 계산은 하자면 영화의 종류, 영화에 적용된 할인 정책, 할인 정책이 적용되기 위한 할인 조건으로 추상화할 수 있다. 여기서 할인 정책, 할인 조건은 일종의 역할이 되며, 할인 정책은 특정 금액 할인 객체과 퍼센트 할인 객체가 그 역할을 상황에 따라 대신할 수 있으며, 할인 조건은 당일 첫 상영 영화 조건 객체, 기간 조건 객체가 그 역할을 상황에 따라 대신할 수 있다.

다시 말해, 추상화 계층 만을 이용하며 협력이라는 관점에서 세부적인 사항(금액 할인 정책, 퍼센트 할인 정책) 등 을 무시하고 추상화에 집중하는 것이 유용하다.

또한 위 예시를 통해 특정 역할을 수행할 수 있는 객체들이 상황에 따라 대신할 수 있다는 점에서 두번째 장점이 들어난다.


반응형