2023.08.06 SUN
65p ~ 77p
5일차 내용 ⬇️
2023.08.04 - [개발 서적 기록/오브젝트_조영호] - 5일차 - 상속과 다형성의 목적
5일차 - 상속과 다형성의 목적
2023.08.04 FRI 50p ~ 64p 4일차 내용 ⬇️ 2023.08.04 - [개발 서적 기록/오브젝트_조영호] - 4일차 - 객체 지향 설계를 위한 자세 4일차 - 객체 지향 설계를 위한 자세 2023.08.03 THU 33p ~ 50p 3일차 내용 ⬇️ 2023.
magenta-ming.tistory.com
추상화의 필요성
추상화를 사용하면, 세부적인 내용을 무시한 채 상위 개념을 쉽고 간단하게 표현할 수 있다.
그래서 세부 사항에 관계 없이,상위 개념만으로도 도메인의 중요한 개념을 설명할 수 있다.
그럼으로써, 어플리케이션 내의 흐름을 유연하게 구성할 수 있다.
예를 들어, 영화와 그 할인 정책 도메인에 대한 상황을 가정해보고자 한다.
하나의 영화에는 하나의 할인 정책이 적용된다.
이 할인 정책은, 가격 할인 정책이 될 수도 있고(-3,000원 처럼), 비율 할인 정책이 될 수도 있다.(-30% 처럼)
가격 할인 정책과 비율 할인 정책을 각각의 클래스로, 부모를 공유하지 않는, 추상화하지 않은 클래스로 선언할 수도 있다.
하지만 두 클래스는 세부적인 부분을 제외하고는 매우 공통적인 구조를 가질 것이고, 각각의 영화는 둘 중 어떤 클래스를 선택할 것인지 정의하기 어렵다.
따라서 추상화를 사용해서, 할인 정책이라는 부모로 추상화 시킨다면, 각 영화는 세부적인 할인 내용을 무시하고 도메인의 흐름을 구성할 수 있다.
더불어서, 상위 개념을 간단하게 표현하는 것은 결국 설계를 유연하게 만든다.
추상화로 상위 개념을 표현했기 때문에, 세부적인 요구 사항이 변경되어도, 상위 개념은 유지되므로 기존 구조를 수정하지 않고 새로운 기능을 추가하고 확장할 수 있다.
위에서 예로 들었던 영화의 예제 또한,
다른 세부적인 할인 정책이 추가되더라도, 추상화한 할인 정책을 가져다쓰는 도메인들에는 영향이 없게되므로, 수정 없이 확장할 수 있다.
코드를 재사용하는 또다른 방법, 합성 composition
합성은 인터페이스에 정의된 메시지를 통해서만 코드를 재사용하는 방법이다.
다른 객체의 인스턴스를 자신의 인스턴스 변수로 포함해서 재사용하는 방법이다.
만약, 위의 영화 예제라면, 영화 객체는 인스턴스 변수로 할인 정책 객체 인스턴스를 가지도록 해 합성을 사용할 수 있다.
public class Movie {
DiscountPolicy discountPolicy;
...
}
합성은 상속이 가지는 두가지 문제점을 해결할 수 있다.
1. 상속은 캡슐화를 위반한다.
자식이 부모를 상속하기 위해서는, 부모의 내부 구조를 잘 알고 있어야한다.
2. 상속은 설계가 유연하지 않을 수 있다.
상속은 실행 시점에 객체의 종류를 변경할 수 없다.
만약, 영화 예제에서, 영화 객체가 상속을 사용했다면, 영화 클래스는 가격할인영화 클래스, 비율할인영화 클래스로 자식 클래스를 가질 수 있다.
자식 클래스인 가격할인영화 클래스, 비율할인영화 클래스는 부모 클래스인 영화 클래스가 내부적으로 할인을 적용하기 위해서 호출하는 다른 메서드가 있다던지의 내용을 알아야하므로 캡슐화를 위반하게 된다.
또, 실행 시점에서, 가격할인 클래스를 사용하고 있는 곳에서 비율할인영화 클래스로 바꾸고 싶다면, 가격할인 클래스의 상태를 복사해야한다.
합성은 위 두가지의 문제점을 모두 해결한다.
1. 합성은, 인터페이스에 정의된 메시지를 통해서만 재사용하므로 구현을 캡슐화 할 수 있다.
2. 합성은, 의존하고 있는 인스턴스 변수의 인스턴스만 교체하면 되므로, 유연한 설계를 가질 수 있다.
합성은 상속의 문제점을 보완하고 있지만, 상속 또한 코드 재사용에 유리하고, 추상화하기 좋다.
따라서, 대부분의 설계에서는 상속과 합성을 함께 사용해야한다.
역할, 책임, 협력이 객체지향을 만든다.
협력은, 객체들이 어플리케이션의 기능을 구현하기 위해 수행하는 상호작용이다.
책임은, 객체가 협력에 참여하기 위해서 수행하는 로직이다.
역할은, 객체들이 협력 안에서 수행하는 책임들이 모인 것이다.
구현의 관점에서 클래스, 상속, 바인딩 등으로 객체 지향을 고려할 수 있다.
구현 처럼 세부적이지 않은, 더 큰 객체지향의 관점에서는, 역할, 책임, 협력이 객체지향을 만든다.
왜냐하면, 객체 지향의 본질은 협력하는 객체들의 공동체를 창조하는 것이기 때문이다.
협력을 통한 다른 객체로의 요청
협력을 통해서 기능을 구현할 수 있다. 어떤 객체가 다른 객체에게 필요한 것을 요청하는 행위가 협력이다.
협력을 통해 요청할 때에는, 메시지 전송이라는 수단을 사용해 소통할 수 있다.
메시지가 수신되면, 요청을 받은 객체는 메서드를 수행해서, 자신의 독립적인 로직에 따라 요청에 응답한다.
요청한 객체는 요청만 보냈을 뿐, 요청받은 객체가 처리할 로직을 결정할 수 없다.
자율성을 보장할 수 있는 협력을 해야한다.
객체들 간에 협력이 이루어진다는 것은, 어떤 하나의 객체가 모든 로직을 스스로 처리하지 않는다는 것을 의미한다. 적합한 객체에 처리를 위임하는 것이다.
하지만, 다른 객체에 처리를 위임하면 다른 객체에 의존적인, 수동적인 객체가 될 수 있다.
따라서, 내부 구현을 캡슐화해야한다.
내부 구현을 알지 못하게 만들어, 변경에 대한 영향을 줄여 자율적인 객체로 만들어야한다.
협력은 문맥을 결정한다.
객체가 참여하는 협력이, 객체를 구성하는 행동과 상태 모두를 결정한다.
따라서, 협력은 객체 설계에 대한 문맥을 제공한다.
예를들어, 영화 예제에서, 영화 객체는 할인 정책과의 협력을 통해, 영화에 할인 정책을 적용한다는 문맥을 알 수 있다.
또, 이 영화 객체가 결제 객체와 협력하게 된다면, 영화에 결제 기능을 적용한다는 문맥을 알 수 있다.
객체 지향을 생각하면, 코드를 재사용하는 개념을 당연히 많이 떠올린다.
하지만, 그 재사용하는 가장 대표적인 방법이 합성이라는 것을 몰랐다.
당연히, 프로젝트에서는 "일기는 이미지를 가지고 있다"라는 것 자체가 일기 도메인 객체가, 내부에 인스턴스 변수로 이미지 인스턴스를 가지고 있는 형태로 구성했다. 그것이 합성한 행위라는 것을 몰랐다.
앞으로도 개발할때 합성하는 방법을 많이 사용하겠지만, 그 합성하는 로직이 외부 객체에 의존적이지는 않는지(물론 많이 의존하고 있다...) 한번 더 고민해봐야겠다.
'개발 서적 기록 > 오브젝트_조영호' 카테고리의 다른 글
8일차 - 추상화를 통한 역할 부여 그리고 책임 중심 설계 (0) | 2023.08.09 |
---|---|
7일차 - 적절한 책임과 적합한 역할 (0) | 2023.08.08 |
5일차 - 상속과 다형성의 목적 (0) | 2023.08.04 |
4일차 - 객체 지향 설계를 위한 자세 (0) | 2023.08.04 |
3일차 - 캡슐화를 통해 결합도 낮추기 (0) | 2023.08.02 |