전통적인 관점의 객체지향
커피 주문을 위해 협력하는 사람들

사람들은 다른 사람과 협력하는 과정에서 특정한 역할을 부여받는다.
- 역할 : 어떤 협력에 참여하는 특정한 사람이 협력 안에서 차지하는 책임이나 임무
- 역할이라는 단어는 의미적으로 책임이라는 개념을 내포함.
협력 속에 사는 객체
객체지향 애플리케이션의 윤곽을 결정하는 것은 역할, 책임, 협력이지만 실제로 협력에 참여하는 주체는 객체임. 협력 공동체의 일원으로서 객체는 다음과 같은 두 가지 덕목을 갖춰야 함.
- 협력성 다른 객체의 명령에 복종하는 게 아닌, 요청에 응답하는 것임. 어떤 방식으로 응답할지는 객체 스스로 판단하고 결정함.
- 자율성 다른 객체와 조화롭게 협력할 수 있을 만큼 충분히 개방적인 동시에 협력에 참여하는 방법을 스스로 결정할 수 있을 만큼 충분히 자율적인 객체를 만들어야 함. 이때, 객체가 수신된 메시지를 처리하는 방법을 메서드라고 부름.
객체지향의 본질
- 객체지향이란 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할하는 방법.
- 자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미.
- 객체는 시스템의 행위를 구현하기 위해 다른 객체와 협력함. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 책임의 집합임.
- 객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 메서드를 자율적으로 선택.
- 핵심은 적절한 책임을 수행하는 역할 간의 유연하고 견고한 협력 관계를 구축하는 것임.
- 객체지향에서 중요한 것은 동적으로 변하는 객체의 상태와 상태를 변경하는 행위임.
이상한 나라의 객체
객체는 상태(state), 행동(behavior), 식별자(identity)를 지닌 실체로 보는 것이 효과적임.
상태
- 모든 객체의 상태는 단순한 값과 객체의 조합으로 표현할 수 있음.
- 값(value)는 숫자, 문자열, 날짜, 시간, 금액 등과 같이 변하지 않는 양을 모델링함. 값의 상태는 변하지 않기 때문에 불변 상태를 가진다고 말함.
- 이때 객체의 상태를 구성하는 모든 특징을 통틀어 프로퍼티(property)라고 함. 프로퍼티는 앨리스의 키, 위치, 음료 등 정적인 존재임.
- 반면 프로퍼티 값(property value)은 시간이 흐름에 따라 변하기 때문에 동적임.
- 즉, 상태는 특정 시점에 객체가 가지고 있는 정보의 집합으로 객체의 구조적 특징을 표현함. 객체의 상태는 객체에 존재하는 정적인 프로퍼티와 동적인 프로퍼티 값으로 구성됨. 객체의 프로퍼티는 단순한 값과 다른 객체를 참조하는 링크(link)로 구별할 수 있음.
- 객체는 스스로의 행동에 의해서만 상태가 변경되는 것을 보장함으로써 객체의 자율성을 유지함.
행동
- 객체의 행동은 객체의 상태를 변경시키지만 행동의 결과는 객체의 상태에 의존적임. - 객체의 행동은 상태에 영향을 받는다. - 객체의 행동은 상태를 변경시킨다.
- 객체의 행동은 객체가 협력에 참여할 수 있는 유일한 방법임. 객체는 협력에 참여하는 과정에서 자기 자신의 상태뿐만 아니라 다른 객체의 상태 변경을 유발할 수 있음. - 객체 자신의 상태 변경 - 행동 내에서 협력하는 다른 객체에 대한 메시지 전송
- 즉 행동이란 외부의 요청 또는 수신된 메시지에 응답하기 위해 동작하고 반응하는 활동임.
- 활동의 결과로 객체는 자신의 상태를 변경하거나 다른 객체에 메시지를 전달할 수 있음.
- 객체는 상태를 캡슐 안에 감춰둔 채 외부로 노출하지 않음. 객체가 외부에 노출하는 것은 행동뿐이며, 외부에서 객체에 접근할 수 있는 유일한 방법 역시 행동뿐이다. (상태 캡슐화)
식별자
- 객체란 인간의 인지 능력을 이용해 식별 가능한 경계를 가진 모든 사물을 의미. 객체가 식별 가능하다는 것은 객체를 서로 구별할 수 있는 특정한 프로퍼티가 객체 안에 존재하는 것을 의미.
- 이 프로퍼티를 식별자라고 함.
- 값과 객체의 가장 큰 차이점은 값은 식별자를 가지지 않지만 객체는 식별자를 가진다는 점임.
- 동등성(equality) - 상태를 이용해 두 값이 같은지 판단할 수 있는 성질
- 동일성(identical) - 식별자를 기반으로 객체가 같은지를 판단할 수 있는 성질
- 객체는 가변 상태임. 타입이 같은 두 객체의 상태가 완전히 똑같더라도 두 객체는 독립적인 별개의 객체로 다뤄야 함.
- 즉 식별자란 어떤 객체를 다른 객체와 구분하는 데 사용하는 객체의 프로퍼티임. 값은 동등성 검사를, 객체는 동일성 검사를 통해 두 인스턴스를 비교할 수 있음.
객체
- 특정한 개념을 적용할 수 있는 구체적인 사물의 의미.
- 객체는 상태를 가지며 상태는 변경 가능함.
- 객체의 상태를 변경시키는 것은 객체의 행동임. - 행동의 결과는 상태에 의존적이며 상태를 이용해 서술할 수 있음 - 행동의 순서가 실행 결과에 영향을 미침.
- 객체는 어떤 상태에 있더라도, 명확한 경계를 가진다면 유일하게 식별 가능함.
- 객체가 외부에 제공하는 행동의 대부분은 쿼리와 명령으로 구분. - 쿼리(query) - 객체의 상태를 조회. - 명령(command) - 객체의 상태를 변경.
기타
- 상태를 먼저 결정하고 행동을 나중에 결정하는 방법은 설계에 나쁜 영향을 미침. ❶ 캡슐화 저해. 상태에 초점을 맞추면 상태가 객체 내부로 깔끔하게 캡슐화되지 못하고 공용 인터페이스에 그대로 노출되어버릴 확률이 높아짐. ❷ 객체가 필요한 이유는 애플리케이션의 문맥 내에서 다른 객체와 협력하기 위해서임. 하지만 상태를 먼저 고려하면 협력에서 멀리 벗어난 채 객체를 설계하게 만듦. ❸ 객체의 재사용성이 저하됨. 상태에 초점을 맞춘 객체는 다양한 협력에 참여하기 어렵기 때문에 재사용성이 저하됨.
- 의인화 - 현실 속 객체와 소프트웨어 객체 사이의 가장 큰 차이점은 현실 속에서는 수동적인 존재가 소프트웨어 객체로 구현될 때는 능동적으로 변한다는 것임.
- 은유 - 은유는 실제로 적용되지 않는 한 가지 개념을 이용해 다른 개념을 서술하는 대화의 한 형태임. 은유는 표현적 차이라는 논점과 관련성이 깊다. 여기서 차이란 소프트웨어에 대해 사람들이 생각하는 모습과 실제 소프트웨어의 표현 사이의 차이를 의함.
타입과 추상화
추상화
- 실제의 사물에서 자신이 원하는 특성만 취하고 필요 없는 부분을 추려 핵심만 표현하려는 행위.
- 복잡한 현실을 단순화하기 위해 사용하는 인간의 가장 기본적인 인지 수단.
- 추상화 하는 방법 ❶ 구체적인 사물들 간의 공통점은 취하고 차이점은 버리는 일반화를 통해 단순화시킴 ❷ 중요한 부분은 강조하고 불필요한 세부 사항을 제거함으로써 단순화시킴. → 추상화는 복잡성을 이해하기 쉬운 수준으로 단순화하는 것이 목적임.
- 개념(concept) - 공통점을 기반으로 객체들을 묶기 위한 그릇. 개념을 이용해 공통점을 가진 객체들을 분류할 수 있다는 아이디어는 객체지향의 복잡성을 극복하는 데 사용됨.
- 개념의 세 가지 관점 : 심볼(symbol) - 개념을 가리키는 간략한 이름이나 명칭 ex) 트럼프 내연(intension) - 개념의 완전한 정의. 객체가 개념에 속하는지 여부를 확인. ex) 몸이 납작하고 네모난 모습 외연(extension) - 개념에 속하는 모든 객체의 집합 ex) 정원사, 병사, 신하 etc
- 분류(classification) - 개념을 이용하여 객체를 여러 그룹으로 나눈 것. 객체에 특정한 개념을 적용하는 작업.
타입
타입은 개념과 동일함. 타입이란 우리가 인식하고 있는 다양한 사물이나 객체에 적용할 수 있는 아이디어나 관념을 뜻함.
- 데이터 타입 - 작업을 위해 데이터를 메모리로 불러들일 때(0과 1의 행렬), 데이터를 목적에 따라 분류하기 시작하면서 데이터가 잘못 사용되지 않도록 제약사항을 부과하기 위해 생긴 것. 즉, 데이터 타입은 메모리 안에 저장된 데이터의 종류를 분류하는 데 사용하는 메모리 집합에 관한 메타데이터.
- 객체와의 관계 - 타입은 데이터임. 데이터는 상태임. 객체는 데이터가 아님. 객체에서 중요한 것은 객체의 행동임. 객체가 협력을 위해 어떤 책임을 지녀야 하는지를 결정하는 것이 객체지향 설계의 핵심.
- 객체가 어떤 행동을 하느냐에 따라 객체의 타입이 결정됨.
- 객체의 타입은 객체의 내부 표현과는 아무런 상관이 없음. 객체의 내부 표현 방식이 다르더라도 행동이 동일하다면 그 객체들은 동일한 타입에 속함.
- 여기서 동일한 행동이란 동일한 책임을 의미. 동일한 책임이란 동일한 메시지 수선을 의미함. 다만, 내부 표현 방식이 다르기 때문에 동일한 메시지를 처리하는 방식은 다름(다형성).
- 책임-주도 설계(Responsibility-Driven Design) - 객체가 외부에 제공해야 하는 책임(데이터가 아닌 행동)을 먼저 결정하고 그 책임을 수행하는 데 적합한 데이터를 나중에 결정.
일반화/특수화
- 일반적인 타입 - 특수한 타입이 가진 모든 행동들 중에서 일부 행동만을 가지는 타입 ex) 트럼프
- 특수한 타입 - 일반적인 타입이 가진 모든 타입을 포함하지만 거기에 더해 자신만의 행동을 추가하는 타입 ex) 트럼프 인간

- 일반적인 타입을 슈퍼타입(Supertype), 특수한 타입을 서브타입(Subtype)이라고 함.
- 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 행위적 호환성을 만족시켜야 함. → 서브타입은 슈퍼타입의 행위에 추가적으로 특수한 자신만의 행동을 추가. 슈퍼타입의 행동은 서브타입에게 자동으로 상속.
동적 모델과 정적 모델
- 동적 모델 - 객체가 살아 움직이는 동안 상태가 어떻게 변하고 어떻게 행동하는지를 포착하는 것.
- 정적 모델 - 객체가 속한 타입의 정적인 모습을 표현.
- 객체지향에서 객체 관점의 동적 모델과 객체를 추상화한 타입 관점의 정적 모델을 적절히 혼용해야 함. 생각의 흐름은 동적 모델에서 정적 모델로 흘러야 함.
- 정적인 관점에서 접근할 때 - 클래스 작성 시점, 동적인 모델을 탐험할 때 - 실제 애플리케이션을 실행해 객체의 상태 변경을 추적하고 디버깅하는 시점. ex) 정적 - 프로그래머 클래스, 동적 - 책 읽고, 코드치고, 공부하고
역할, 책임, 협력
협력
- 협력의 본질은 요청과 응답으로 연결되는 사람들의 네트워크임.
- 협력은 한 사람이 다른 사람에게 도움을 요청할 때 시작됨.
- 요청과 응답은 협력에 참여하는 객체가 수행할 책임을 정의함.
책임
- 어떤 대상에 대한 요청은 그 대상이 요청을 처리할 책임이 있음을 암시.
- 책임은 객체에 의해 정의되는 응집도 있는 행위의 집합으로, 객체가 알아야 하는 정보와 객체가 수행할 수 있는 행위에 대해 개략적으로 서술한 문장임.
- 객체의 책임은 아는 것(knowing)과 하는 것(doing)으로 구성됨. - 아는 것 * 개인적인 정보 * 관련된 객체 * 자신이 유도하거나 계산할 수 있는 것 - 하는 것 * 객체를 생성하거나 계산을 하는 것 * 다른 객체의 행동을 시작시키는 것 * 다른 객체의 활동을 제어하고 조절하는 것
- 책임은 객체의 외부에 제공해 줄 수 있는 정보(아는 것)와 외부에 제공해 줄 수 있는 서비스(하는 것)의 목록임.
- 책임은 객체의 공용 인터페이스(public interface)를 구성함.
- 객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메시지를 수신할 것인지를 결정하는 것으로부터 시작함.
역할
- 책임의 집합은 객체가 협력 안에서 수행하는 역할을 암시함.
- 역할을 사용하면 하나의 협력으로 추상화할 수 있음 → 역할은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식
- 역할을 대체할 수 있는 객체는 동일한 메시지를 이해할 수 있는 객체로 한정됨.
- 역할의 개념을 사용하면 유사한 협력을 추상화해서 인지 과부하를 줄일 수 있음.
- 유연성과 재사용성이 높아짐.
- 역할의 대체 가능성은 행위 호환성을 의미하고, 행위 호환성은 동일한 책임의 수행을 의미.
설계
- 객체가 존재하는 이유는 행위를 수행하며 협력에 참여하기 위함. 따라서 객체의 행동, 즉 책임이 매우 중요함.
- 객체에 책임 할당 → 객체가 행동을 결정 → 필요한 데이터 고민 → 클래스 구현 방법 결정
객체지향 설계 기법
- 책임-주도 설계 - 객체지향 설계란 애플리케이션의 기능을 구현하기 위한 협력 관계를 고안하고, 협력에 필요한 역할과 책임을 식별한 후 이를 수행할 수 있는 적절한 객체를 식별해 나가는 과정. - 객체지향 설계의 핵심은 올바른 책임을 올바른 객체에게 할당하는 것. - 책임 주도 설계는 객체의 책임을 중심으로 시스템을 구축하는 설계 방법 - 각 객체가 책임을 수행하는 중에 필요한 정보나 서비스를 제공해줄 협력자를 찾아 해당 협력자에게 책임을 할당하는 순차적인 방식
- 디자인 패턴 - 책임주도 설계의 결과를 표현.
- 테스트-주도 개발 - 테스트 주도 개발은 테스트를 작성하는 것이 아니라 책임을 수행할 객체 또는 클라이언트가 기대하는 객체의 역할이 메시지를 수신할 때 어떤 결과를 반환하고 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대를 코드의 형태로 작성한 것. - 다양한 설계 경험과 패턴에 대한 지식이 없는 사람들의 경우에는 온전한 혜택을 누리기가 어려움.
책임과 메시지
- 책임은 요청을 처리하기 위해 객체가 수행하는 행동을 말함.
- 자율적인 책임의 특징은 객체가 '어떻게(how)' 해야 하는가가 아니라 '무엇(what)'을 해야 하는가를 설명한다는 것.
- 메시지는 객체들이 서로 협력하기 위해 사용할 수 있는 유일한 의사소통 수단임.
- 메시지를 처리할 수 있다는 건 객체가 해당 메시지에 해당하는 행동을 수행해야 할 책임이 있다는 것을 의미함.
- 메서드는 메시지를 처리하기 위해 내부적으로 선택하는 방법을 말함.
다형성
- 다형성이란 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것을 의미.
- 다형성에서 중요한 건 메시지 송신자의 관점임. 송신자 관점에선 객체들이 동일한 책임을 공유, 수행하고 있는 것임.
- 다형성은 동일한 역을 수행할 수 있는 객체들 사이의 대체 가능성을 의미함.
- 다형성은 객체들의 대체 가능성을 이용해 설계를 유연하고 재사용 가능하게 만듦.
- 메시지는 송신자와 수신자 사이의 결합도를 낮춤으로써 설계를 유연하고, 확장 가능하고, 재사용 가능하게 만듦.
- 객체지향은 정적인 클래스가 아닌 메시지를 주고받는 동적이고 협력적인 객체들의 관점에서 시스템을 바라봐야 함.
- 묻지 말고 시켜라. what/who 사이클은 어떤 객체가 필요한지를 생각하지 말고 어떤 메시지가 필요한지를 먼저 고민하라고 조언함.
- 객체는 다른 객체의 상태를 묻지 말아야 함.
인터페이스
- 인터페이스란 어떤 두 사물이 마주치는 경계 지점에서 서로 상호작용할 수 있게 이어주는 방법이나 장치를 의미함.
- 텔레비전을 시청하기 위해 가장 많이 사용하는 인터페이스는 리모컨이며, 엘리베이터는 버튼이 이에 해당함.
- 인터페이스의 3가지 특성 - 인터페이스의 사용법만 알고 있으면 대상의 내부 구조나 동작 방법을 몰라도 상호작용이 가능. - 인터페이스가 변경되지 않고 단순히 내부 구성이나 작동 방식이 변경되는 것은 인터페이스 사용자에게 아무런 영향도 미치지 않음. - 인터페이스가 동일하기만 하면 어떤 대상과도 상호작용할 수 있음.
- 내부에서만 접근 가능한 사적인 인터페이스와 구분하기 위해 외부에 공개된 인터페이스를 공용 인터페이스라고 함.
- 객체지향 세계에서 내부 구조와 작동 방식을 가리키는 고유 용어는 구현임. 객체의 상태와 행동은 구현에 해당함.
- 인터페이스와 구현을 분리해야 하는 이유는 소프트웨어는 항상 변경되기 때문임.
- 객체지향의 출발점은 책임을 자율적으로 만드는 것임.
객체 지도
객체지향 세계를 구축하기 위해서는 사용자에게 제공할 기능과 기능을 담을 안정적인 구조가 준비되어야 함.
도메인 모델 (구조)
- 도메인 모델링 : 구조를 수집하고 표현하기 위한 기법
- 도메인(사용자가 프로그램을 사용하는 대상 분야) + 모델(대상을 단순화해서 표현한 것) = 사용자가 프로그램을 사용하는 대상 영역에 관한 지식을 선택적으로 단순화하고 의식적으로 구조화한 형태.
- 훌륭한 디자인이란 사용자가 예상하는 방식에 따라 정확하게 반응하는 제품을 만드는 것

- 도메인 모델이란 사용자들이 도메인을 바라보는 관점이며, 설계자가 시스템의 구조를 바라보는 관점인 동시에 소프트웨어 안에 구현된 코드의 모습 그 자체임.
- 객체지향을 이용하면 도메인에 대한 사용자 모델, 디자인 모델, 시스템 이미지 모두가 유사한 모습을 유지하도록 만드는 것이 가능함(완전연결성).
유스케이스 (기능)
- 유스케이스 모델링 : 기능을 수집하고 표현하기 위한 기법
- 기능적 요구사항이란 시스템이 사용자에게 제공해야 하는 기능의 목록을 정리한 것.
- 유스케이스란 사용자의 목표를 달성하기 위해 사용자와 시스템 간에 이뤄지는 상호작용의 흐름을 텍스트로 정리한 것. 즉, 사용자와 시스템 간의 상호작용을 보여주는 텍스트임.
- 유스케이스는 설계 기법도, 객체지향 기법도 아님. 단지 사용자가 바라보는 시스템의 외부 관점만을 표현하는 기법임. 시스템의 내부 구조나 실행 메커니즘에 관한 어떤 정보도 제공하지 않음.
예시


시스템에 할당된 커다란 책임은 시스템 안의 작은 규모의 객체들이 수행해야 하는 더 작은 규모의 책임으로 세분화함. 도메인 모델을 중심으로 객체 구조를 설계하고 유스케이스의 기능을 객체의 책임으로 분배함.
- 도메인 모델에 포함된 개념을 은유하는 소프트웨어 객체를 선택.
- 협력을 완성하는 데 필요한 메시지를 식별하며 객체들에게 책임 할당.
- 도메인 속성의 모델을 클래스의 인스턴스 변수로, 협력 안에서의 책임을 클래스의 메서드로 변환하는 등 협력에 참여하는 객체를 클래스, 속성, 메소드로 구현.
책임 할당의 기본 원칙은 책임을 수행하는 데 필요한 정보를 가진 객체에게 그 책임을 할당하는 것. 이것은 관련된 상태와 행동을 함께 캡슐화하는 자율적인 객체를 만듦.
세 가지 상호 연관된 관점
- 개념 관점 개념 관점에서 설계는 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현함. 이 관점은 사용자가 도메인을 바라보는 관점을 반영함. 따라서 실제 도메인의 규칙과 제약을 최대한 유사하게 반영하는 것이 핵심. * 도메인 : 사용자들이 관심을 가지고 있는 특정 분야나 주제, 소프트웨어는 도메인에 존재하는 문제를 해결하기 위해 개발.
- 명세 관점 명세 관점에 이르면 사용자의 영역인 도메인을 벗어나 개발자의 영역인 소프트웨어로 초점이 옮겨짐. 즉, 객체의 인터페이스를 바라봄('무엇을 할 수 있는가'에 초점). 명세 관점과 구현 관점을 명확하게 분리해야 함.
- 구현 관점 구현 관점의 초점은 객체들이 책임을 수행하는 데 필요한 동작하는 코드를 작성하는 것. 프로그래머는 객체의 책임을 '어떻게' 수행할 것인가에 초점을 맞추며 인터페이스를 구현하는 데 필요한 속성과 메서드를 클래스에 추가함.
클래스는 세 가지 관점을 모두 수용할 수 있도록 개념, 인터페이스, 구현을 함께 드러내야 함. 동시에 코드 안에서 세 가지 관점을 쉽게 식별할 수 있도록 깔끔하게 분리해야 함.
마치며
아직은 배운 게 많이 없어 객체지향에 대해 오해를 할 것도 없지만 그래도 좀 더 객체지향에 대해 정확하고 자세하게 알고자 읽었다. 확실히 이 책을 읽으니까 객체지향이란 게 어떤 건지 감이 오는 것 같다. 객체지향이란 캡슐화되어 재사용하기 편하고, 현실 세계를 은유적으로 표현함으로써 인간이 가지는 인식의 한계를 극복하기 위한 방법이다. 결국 객체지향이라 검색했을 때 나오는 말과 똑같은 소리를 하고 있지만 내가 이해하고 말하는 것과 단순히 요약정리해 놓은 걸 읽은 것과는 이해의 깊이가 다르다고 생각한다. 추후 내가 개발 공부를 더 해서 나중에 이 책을 다시 읽었을 때 어떻게 받아들일지 궁금하다.
