객체 지향의 사실과 오해
객체 지향은 무엇인가가
누가 어떤 책임을 수행하고, 누구로부터 메시지를 받을 건지 결정하는 것으로부터 시작한다.
1. 현실 세계와 객체 지향
- 목적을 달성하기 위해
메시지
를 주고 받으며협력
하는 객체들.
역할, 책임, 협력
혼자 하기보다 여럿이서 같이 요청 메시지
를 보내 해결한다. 다른 사람과 협력하듯, 객체 또한 그러하다.
또한 각 사람은 각각의 역할, 역할에 따른 책임이 존재한다.
캐셔: 주문 받기→ 주문 받고, 바리스타에게 요청할 책임
바리스타: 커피 제조→ 커피제조
이에
- 여러 사람(객체)이 동일한 역할이 가능하며, (캐셔 알바가 그만 두면 다른 알바를 구해 캐셔2를만든다.)
- 대체 가능하고
- 책임 수행 방법은 자유로우며 (커피를 머신으로 내리던, 드립으로 내리던)
- 한 사람(객체)이 동시에 여러 역할도 수행할 수 있다.
결국 객체의 역할과 책임(해야할 행동)을 가지고, 요청 메시지를 통해 협력한다. 또한 요청으로 행동한다. 객체는 협력적
이어야 하며( 독단 수행은 금물) 자율적
이어야 한다. (요청에 따라 스스로 판단, 행동
)
행동으로 상태(특정 시점에 가진 정보)를 결정하며, 상태를 공용 인터페이스에 보이지 않게 캡슐화 해야 한다.
타입(for 추상화)은 객체를 분류하는 체이며, 행동→ 타입 결정. 동일한 행동=동일한 책임= 동일한 타입/ class는 타입 중 하나고, 타입을 나누는 기준은 객체가 수행하는 행동이다.
즉, class는 객체를 분류하기 위해 만들며, 객체가 수행하는 행동으로 분류된다. → 일반화(공통된 것)/특수화는 더 특이한 행동을 하느냐에 따라 갈리기 때문이다.
상태, 행동을 지닌 객체
객체의 자율성
은 객체의 내부/외부를 명확하게 구분하는 것으로부터 나온다.
즉, 사적 부분은 간섭이 없어야 하며 허락된 수단
으로만 다른 객체와 의사소통
해야한다.
각각 보내는 메시지를 처리하는 방법은 메서드
라고 하며, 이 메서드를 분리하는 것은 객체의 자율성을 높인다. (캡슐화)
협력을 위해 각 자율적인 객체는 역할과 책임을 다하고, 서로 주어진 수단으로 소통하며 메시지를 처리하기 위해 메서드를 사용한다.
객체는 다 구별되며, 자율적이다. 자신의 상태를 스스로 행동하여 변경하고, 타인에게 함부로 간섭받을 수 없다.
2. 이상한 나라의 객체
상태, 행동, 식별자
객체는 저장된 상태, 실행 가능한 코드를 통해 구현된다.
1) 상태(특정 시점에 객체가 가진 정보의 집합)
: (배고프면→ 먹는다.) 객체의 행동 방식을 이해할 수 있다.
배고프니까 먹으니. 상태를 알면 왜 그렇게 행동(먹는다)하는지 알 수 있다.
또한 객체는 스스로
상태를 변경해야 한다. (주도적)→ 그래야 자율성
을 유지하기에.
객체 상태 조회 = 쿼리
객체 상태 변경 = 명령
객체를 접근할 수 있은 유일
한 방법은 그 객체가 제공하는 행동 뿐이다.
즉, 객체 자신이 제공하는 명령, 쿼리 버튼으로 구성된 인터페이스만을 통해 사용자가 객체에 접근할 수 있다.
상태 캡슐화
잘 정의된 행동 집합을 캡슐화하면 자율성은 높아지고, 협력을 단순하고도 유연하게 만들 수 있다. 즉 상태를 캡슐화 해야한다.
ex) 앨리스(객체)가 빵(객체)을 먹을 때(협력), 앨리스에게 eatBread()가 오면, 음료에게 eaten(qunatity)라고 요청을 보낸다. 이때 각 앨리스와 빵에 대한 상태
는 알 수 없다. 그저 메시지를 주고 받았다는 사실 뿐. 이것이 중요하다.
-프로퍼티 (상태를 구성하는 모든 특징)
: 앨리스(객체)의 몸무게가 40, 위 상태가 배고픔. 이 프로퍼티들은 고정적이지만, 각각의 값은 동적이다. 빵(객체)을 먹으면 빵의 프로퍼티인 양이 0이 된다. 이때 앨리스는 몸무게가 41, 배고픔이 배부름으로 변했다. 이후 빵-앨리스의 관계가 없어지므로 연결이 사라진다. 이 연결을 Link라고 하며, 객체 사이에는 이 Link
가 있어야 요청을 받고 보낼 수 있다.
즉, Link를 통해서만 객체는 메시지를 주고 받을 수 있다.
즉, 객체의 상태 = 정적인 프로퍼티+동적으로 바뀌는 프로퍼티 값
객체의 프로퍼티 = 단순한 값(속성)+ 다른 객체를 참조하는 Link
식별자 = 구별할 수 있는 프로퍼티
식별자( 서로 구별할 수 있는 특정 프로퍼티)
객체는 식별자가 있기에 구분 가능하며, 값은 식별자가 없기에 구별할 수 있다.
- 값은 상태가 같으면 같다고 판단한다. 왜냐하면 값의 상태가 변하지 않기 때문이다.
- 객체는 시간에 따라 상태가 변경된다. 따라서 식별자가 따로 필요하다.
→ 식별자를 통해 동일 검사를 하여 인스턴스 비교가 가능하다.
2) 행동
상태와, 행동
행동은 상태를 변경시킨다. 행동은 상태에 영향을 받는다.
상태가 변경되면 행동하고 행동하면 상태가 변경되기도 한다.
협력, 행동
협력을 하는 유일한 방법 = 요청
을 보내는 것. 요청을 받으면 행동한다. 행동하면 상태가 변한다. 그러나 그것이 다른 객체의 상태 변경을 유발할 수 있다.
즉, 객체가 행동하면 객체 자신 상태가 변경되거나 협력하는 다른 객체에게 요청하는 결과가 일어난다.
협력→요청→행동→상태 변경 or 다른 객체에 요청→ 행동→ …
행동으로 자신의 상태 변경 or 객체에 메시지 전달, 행동을 통해 협력하므로 이 행동은 외부에 가시적이어야 한다
3) 행동과 상태
객체는 행동에 초점을 둬야 한다.
상태를 집중으로 보면
- 상태를 먼저 결정하면 캡슐화가 저해되고( 공용 인터페이스에 노출)
- 협력에 적합하지 못하며
- 재사용성이 떨어진다. (협력을 못하니)
행동을 결정하고, 그 행동에 적절한 상태를 선택해야 한다. 행동이 상태를 결정한다.
3. 추상화, 타입
1) 개념(=타입) 공통점을 기반으로 객체를 나눌 수 있는 체
개념으로 나뉜 그룹에 속한 객체를 그 개념의 인스턴스라고 한다.
객체=특정한 개념을 적용 가능한 구체적 사물. 개념이 객체에 적용되면, 그 객체를 개념의 인스턴스라고 함.
개념으로 객체를 분류하고, 어떻게 분류할지가 OOP의 품질을 결정한다.
객체가 어떤 타입(개념)인지 결정하는 건 객체가 수행한 행동이며, (즉, 행동으로 타입이 결정된다.→ 같은 행동을 하면 같은 타입에 속한다. 즉, 책임이 같으면 동일한 타입이다. ) 객체의 내부적 표현은 외부로부터 감춰져야 한다.
2) 다형성 (동일 요청에 대해 다른 방식으로 응답하는 능력)
다형적인 객체는 동일한 타입이다.
객체는
- 외부에 제공하는 행동을 생각하고, 책임을 먼저 결정한다.
- 이후 책임을 수행하는 데 적합한 데이터를 나중에 결정하고
- 책임 수행을 위해 필요한 외부 인터페이스 뒤로 데이터를 캡슐화 해야한다.
3) 타입의 계층, 일반화와 특수화
특수하다(서브, 트럼프 인간): 일반인이 하는 것도 다 할수 있는데(엎드리기, 뒤집기) 특이한것(걷다)도 할 수 있다. 그래서 할수 있는 건 많지만, 그 수는 적다.
일반적이다(슈퍼, 트럼프): 다 하는거. (납작 엎드리기, 뒤집기)
→결국 일반화(공통, 다들 하는 것)는 추상화를 위한 것이다.
Class 타입(for 추상화)은 객체를 분류하는 체이며, 행동→ 타입 결정. 동일한 행동=동일한 책임= 동일한 타입/ class는 타입 중 하나고, 타입을 나누는 기준은 객체가 수행하는 행동(책임)이다.
즉 class는 서로 다른 책임을 지녀야 한다.
****즉, class는 객체를 분류하기 위해 만들며, 객체가 수행하는 행동으로 분류된다. → 일반화(공통된 것)/특수화는 더 특이한 행동을 하느냐에 따라 갈리기 때문이다.
4. 협력, 책임, 역할
1) 협력
한 사람이 다른사람에게 도움 요청할때 시작.
연쇄적인 요청, 응답으로 협력한다.
2) 책임 (객체 외부로 제공가능한 정보+서비스) 즉, 공용 인터페이스를 구성.
누군가에 요청한다 = 그 누군가가 요청을 처리할 책임이 있음을 나타낸다.
객체의 책임 = 객체가 무엇을 알고+할 수 있는 지
아는 것(외부로 제공 가능한 정보)
- 개인적인 정보 아는 것
- 관련된 객체 아는 것
- 자신이 유도, 계산할 수 있는 것에 대해 아는 것.
하는 것(외부로 제공 가능한 서비스)
- 객체 생성, 계산 등 스스로 하는 것
- 다른 객체의 행동을 시작 시키는 것
- 다른 객체의 활동을 제어, 조절하는 것
3) 역할
역할은 재사용 가능하며, OOP 설계에서 많이 중요한 요소.
각 재판에서 제각기 다른 객체가 동일한 메시지를 받고, 요청한다. 이걸 다 하나하나 구현한다? ㄴㄴ 추상화로 역할
을 부여하자.
역할은 다른 객체로 대체할 수 있는 일종의 표식이며, 대체하기 위해서는 각 역할이 수신할 수 있는 메시지를 동일하게 이해해야 한다.
즉, 동일한 역할= 동일한 메시지 수신=동일한 책임을 수행한다. (단순, 유연, 재사용 가능)
역할로 협력을 추상화 해서 단순화가 가능하다.
올바른 객체 설계
- 책임(행동)을 결정
- 행동을 수행하기 위해 필요한 데이터 고민
- 클래스 구현 고민.
4) 객체 지향 설계 기법
- 책임 주도 설계 (방법, 절차)
- 사용자에게 제공할 기능을 하는 시스템의 책임 파악
- 시스템 책임을 작은 책임으로 분할
- 분할된 책임을 수행가능한 객체, 역할을 찾아 책임 할당
- 객체 책임을 수행하면서 필요한 정보, 서비스를 제공해줄 협력자 찾기
- 협력자에게 책임 할당하기
- 디자인 패턴 (결과)
- 책임 주도 설계의 결과물, 템플릿.
- TDD
5. 책임과 메시지
객체는 책임
을 다하기 위해 자율적(스스로의 원칙에 따라 행동, 절제하는 것)
으로 행동, 판단한다.
객체는 다른 객체로부터 요청을 수신해야 행동( = 책임 )한다.
그리고 책임이 자율적이어야 객체가 자율적이다. ex) 재판하라는 요청을 받은 재판장이 모자장수에게 증언하라(요청) 한다. 그러면 모자장수는 자율적으로 알아서 증언하면 된다. 하지만 재판장이 장면, 재구성, 표현하라는 여러가지 요청을 하면, 모자장수는 자율적으로 말하는 게 아닌 시키는 대로 다 하는 것.
즉, 상세한 수준의 요청이 아닌 포괄적, 추상적인 요청을 해야한다 (객체 자율성 보장).
그러나 너무 추상적인건 말고 의도가 담기며, 더 다양한 환경에서 재사용할 수 있도록만 해주자.