본 글은 객체지향의 사실과 오해를 읽고난 후 저에게 필요한 내용이나 기억에 남는걸 정리한 문서입니다.
객체지향이란 시스템이 맡아야할 큰 책임을 결국 자율적인 객체들이 각자 책임을 맡고, 자신이 처리할 수 없는 일은 링크를 통해 메세지를 보내서 다른 객체에게 일임하여 협력하는 구조를 뜻한다.
객체의 상태를 구성하는 모든 특징을 통틀어 객체의 프로퍼티라고 한다.
프로퍼티는 변경되지 않고 "정적"이다.
다만, 프로퍼티의 값 자체는 변하기 때문에 "동적"이다.
프로퍼티의 구성은 단순한 값인 속성(식별자 포함) + 다른 객체를 가리키는 링크로 이루어진다.
※ 링크: 객체가 다른 객체를 참조하는 것 => 해당 링크를 통해 메세지를 주고 받음
※ 식별자 기반으로 두 객체의 상태가 다르지만 동일한 객체로 판단하는 성질을 "동일성" 이라고 한다
※ 참조 객체, 엔티티 => 식별자를 지닌 객체 / 값 객체(ex, Integer)은 식별자를 가지지 않는 값
명령: 객체 기계에 상태를 변경하는 명령
쿼리: 객체 기계에 상태를 조회하는 쿼리
※ 명령과 쿼리는 객체가 외부에 제공하는 행동, 해당 방법 이외에 다른 방법으로는 객체 이용할 수 없음 => 직접 객체의 내부 상태에 접근X => 메세지를 통해서만 접근 가능 => 수신 가능한 메세지가 모여 객체의 인터페이스 구성
객체에서 중요한 것은 객체의 행동( 협력하는 객체 간의 책임 측면도 포함 )이며, 상태는 행동의 결과로 초래된 부수효과일 뿐...
결국, 객체의 타입을 결정하는 것은 객체의 행동 / 어떤 데이터를 객체가 가지고 있던 타입 결정에는 영향을 미치지 않는다.
※ 이는 같은 행동을 할 수 있는 동일한 타입에 속한 객체는 내부의 데이터 표현 방식이 다르더라도 동일한 메세지를 수신하고 처리할 수 있음을 의미함 (다만 내부 표현 방식이 다르니 동일한 메세지를 처리하는 방식은 다를 수 있음) => 다형성
두 타입 간에 일반화/특수화 관계가 성립하려면, 한 타입( 서브타입 )이 다른 타입보다 더 특수하게 행동해야 하고, 한 타입( 슈퍼타입 )은 다른 타입보다 더 일반적으로 행동해야한다.
단, 특수한 타입은 일반적인 타입이 할 수 있는 모든 행동을 동일하게 수행할 수 있어야 한다.
이는 곧, 어떤 타입을 다른 타입의 서브타입이라고 말하려면 다른 타입을 대체할 수 있어야 하는 것을 의미한다.
객체의 책임은 크게 '무엇을 알고 있는가' + '무엇을 할 수 있는가' 로 이루어짐
무엇을 알고 있는가 : 관련 객체에 대해 아는 것 or 개인적인 정보에 대한 것
무엇을 할 수 있는가 : 다른 객체의 활동 제어하고 조절 or 객체 생성 계산 등 스스로 하는 것
※ 결국 객체의 책임은 외부에서 접근 가능한 공용 인터페이스의 관점이다. 즉, 책임은 객체가 외부에 제공해 줄 수 있는 정보와 서비스의 목록이다. => 내가 처리할 수 있거나 아는 거면 내가 처리하고, 모르면 관련 객체에게 던져주고
동일한 역할을 수행할 수 있다는 것은 해당 객체들이 협력 내에서 동일한 책임의 집합을 수행할 수 있다는 것을 의미한다.
즉, 동일한 역할을 수행하는 객체들이 동일한 메세지를 수신할 수 있기 때문에 동일한 책임을 수행할 수 있다는 개념 => ( 메세지 == 책임 )
※ 역할을 이용하면 협력을 추상화함으로써 여러 케이스에서 재사용 가능하다.
※ 객체가 역할을 대체 가능하기 위해서는 협력 안에서 역할이 수행하는 모든 책임을 동일하게 수행할 수 있어야 하며, 주어진 책임 이외에 +@로 다른 책임도 수행할 수 있다. ( 일반화와 추상화의 개념 )
해당 객체가 어떠한 방법( 내부 구현 )으로 책임을 수행할 수 만 있다면, 구체적인 방법이나 절차는 객체가 자유롭게 선택할 수 있어야한다.
=> 포괄적이고 추상적인 책임을 선택한다고 능사는 아니다. 책임이 수행 방법을 제한할 정도로 너무 구체적인 것도 문제지만, 협력의 의도를 명확하게 표현하지 못할 정도로 추상적인 것 또한 문제
※ 즉, 자율적인 책임의 특징은 '어떻게 해야하는지'에 대한 것이 아닌 '무엇을 해야하는가'에 대해 설명하는 것!
서로 다른 객체들이 다형성을 만족시킨다는 것은 객체들이 동일한 책임을 공유한다.
즉, 다형성은 동일한 역할을 수행할 수 있는 객체들 사이의 대체 가능성
특정 메세지 => 특정 책임 => 특정 역할 => 해당 행동을 할 수 있는 모든 객체가 속할 수 있음 => 이때 각 객체들은 다형성( 일반화, 추상화 ) 관계에 있다.
인터페이스는 사용법만 알면 내부 구조나 동작 방식을 몰라도 대상 조작 가능
인터페이스 자체 변경하지 않고, 내부 구성이나 작동 방식 변경해도 인터페이스 사용자에게 영향X
대상이 변경되더라도 동일한 인터페이스를 제공하기만 하면 아무런 문제 없이 상호작용 가능
※ 객체끼리 상호작용하는 유일한 방법은 링크를 통한 메세지 전송 => 인터페이스는 필연적으로 해당 객체가 수신할 수 있는 메세지의 목록
※ 인터페이스와 구현의 분리 원칙 : 구현을 변경할 때 외부 파급 효과 최소화를 위해 객체끼리 협력시 공용 인터페이스에만 의존하고, 구현 세부 사항에 의존하면 안된다.
기능 측면의 설계 : 제품이 사용자를 위해 무엇을 할 수 있는가? => 유스케이스 모델링
구조 측면의 설계: 제품의 형태가 어떠해야 하는가? => 도메인 모델링
구조 base 그 위에 기능 얹기
사용자가 프로그램을 사용하는 대상 분야
사용자가 프로그램을 사용하는 대상 영역에 대한 지식을 구조화한 형태
ex) 은행의 '정기예금' 도메인 모델은 정기예금 신청 -> 계좌 -> 이자율 -> 이자 구조를 따르며, 이는 비즈니스 로직이 바뀌지 않는 한 불변한다.
ex) '커피 주문' 도메인 모델은 메뉴판 확인 -> 메뉴 주문 -> 바리스타 -> 커피 구조를 따르며, 이는 비즈니스 로직이 바뀌지 않는 한 불변한다.
사용자와 시스템 간의 상호작용을 보여주는 '텍스트'이다.
중요한 점은, 유스케이스 안에 포함되어있는 상호작용의 흐름 => 하나의 시나리오가 아닌 사용자의 목표와 관련된 모든 시나리오의 집합
다만, 유스케이스는 기능적 요구사항을 사용자의 목표라는 문맥을 중심으로 묶기위한 정리 기법일 뿐
※ 유스케이스의 일차액터: 시스템의 서비스 중 하나를 요청하는 이해관계자로, 시스템과 연동하는 외부 시스템 역시 일차 액터의 범주
우리는 유스케이스에 정리된 시스템의 기능들을 도메인 모델을 기반으로 한 객체들의 책임으로 분배해야한다.
예시: 중도 해지 이자액을 계산하는 기능
1. 도메인 모델 생성: 정기예금 -> 계좌 -> 이자율 -> 이자
2. 해당 기능을 도메인 모델에 메세지와 책임(역할) 기준으로 분배
if) 이자율이 고정 이자율이 아닌 기간에 따른 이자율과 같이 여러가지 경우? => 이자율을 인터페이스로 등록하고, 하부에 구현 객체 만들기 => 다형성, 일반화/구체화, 인터페이스에 의존, 역할