반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 디프만
- 코딩
- kakao
- Redis
- exception
- depromeet
- OAuth
- nGrinder
- C언어
- 코드 트리
- 코딩 테스트
- 자료구조
- Scaffold
- AOP
- 부하 테스트
- pub.dev
- c
- 코딩테스트
- Oidc
- 디프만16기
- Kafka
- 운영체제
- Kotlin
- flutter
- java
- 연습문제
- dip
- 코드트리
- Spring
- Sharding
Archives
- Today
- Total
Nick Dev
[객사오] 1장. 협력하는 객체들의 공동체 본문
반응형
객체지향의 목표는 실세계의 모방이 아니다
- 객제지향 프로그래밍이란 현실 속 존재하는 사물을 최대한 유사하게 모방해 소프트웨어 내부로 옮겨오는 작업이라고 하지만 실제로 그렇지 않다.
- 소프트웨어 객체와 실세계 사물 사이에 존재하는 연관성은 희미
- 그럼에도 실세계에 대한 비유가 객제지향의 다양한 측면을 이해하고 학습하는데 효과적
객체지향의 가장 중요한 개념 3가지
- 역할
- 책임
- 협력
협력
- 특정한 책임을 수행하는 역할들 간의 연쇄적인 요청과 응답을 통해 목표를 달성
- 스스로 해결하지 못하는 문제를 마주치면 도움을 요청함
- 도움은 또 다른 도움 요청을 발생시킴
- 이렇게 연쇄적으로 요청이 발생함
- 요청을 받은 사람은 주어진 책임을 다하면서 요청에 대해 응답함
- 협력의 성공은 특정 역할을 맡은 개인이 얼마나 요청을 성실히 이행하는가에 달려 있음
역할
- 어떤 협력에 참여하는 특정 사람이 협력 안에서 차지하는 책임이나 의무를 의미
- 역할은 의미적으로 책임이라는 개념을 내포
- 캐시어라면 손님으로부터 주문을 받을 책임이 있음
- 즉, 특정 역할은 특정 책임을 암시
- 특징
- 여러 객체가 동일한 역할 수행 가능
- 역할은 대체 가능성을 의미
- 두 객체가 동일 역할을 수행하면 어떤 객체가 역할을 수행하더라도 무관하다
- 각 객체는 책임을 수행하는 방법을 자율적으로 선택 가능
- 동일한 요청에 대해 서로 다른 방식으로 응답할 수 있는 능력 ⇒ 다형성
- 하나의 객체가 동시에 여러 역할을 수행할 수 있음
객체
- 협력에 참여하는 주체는 객체
- 객체는 상태(state)와 행동(behavior)을 함께 지닌 실체다
- 객체가 협력에 참여하기 위해 어떤 행동을 해야 된다면, 그 행동을 하는데 필요한 상태도 함께 지니고 있어야 한다
- 객체의 사적인 부분 → 객체 스스로 관리하고 외부에서 일체 간섭할 수 없도록 차단
- 객체 외부에서는 접근이 허락된 수단을 통해서만 객체와 의사소통해야 함
- 즉, 객체는 다른 객체가 무엇을 수행하는지는 알 수 있지만, 그걸 어떻게 수행하는지는 모른다.
- 예를 들어, 캐시어 라는 객체는 바리스타가 커피를 만들어준다는 건 알지만, 커피를 어떻게 만들어서 줄 지는 모른다
- 핸드 드랍으로 줄지, 머신으로 내려줄지 모른다.
- 그냥 바리스타라는 객체가 어떻게 만들지는 캐시어 객체 입장에서는 알빠노 임
메시지
- 객체지향 세계에 존재하는 단 1가지 의사소통 방식
- 객체는 협력을 위해 다른 객체에게 메시지를 전송하고 다른 객체로부터 메시지를 수신함
메서드
- 객체가 수신된 메서드를 처리하는 방법을 메서드라고 한다
- 어떤 객체에게 메시지를 전송 → 메시지에 대응되는 특정 메서드가 실행된다
- 메시지를 수신한 객체가 런타임 시점에 메서드를 선택할 수 있다는 것
- 이게 다른 프로그래밍 언어와 객체지향 프로그래밍 언어를 구분하는 핵심 특징
- 예시
- 메시지 : 캐시어 → 바리스타 로 전달된 커피 제조 요청
- 메서드 : 바리스타가 커피를 제조하는 구체적인 방법
- 외부 요청이 무엇인지 표현하는 메시지와 요청을 처리하는 구체적 방법인 메서드를 분리하는 것은 객체의 자율성을 높여주는 핵심 메커니즘이다.
메시지와 메서드 예시
메시지 : 메서드 호출을 의미..? → 무엇을 할지
메서드 : 메서드 내용을 의미..? → 어떻게 할지
// 바리스타 인터페이스
interface Barista {
Coffee makeCoffee(String menuName); // 메시지의 형태를 정의
}
// 초보 바리스타
class JuniorBarista implements Barista {
@Override
public Coffee makeCoffee(String menuName) { // 메서드 구현
return switch (menuName) {
case "아메리카노" -> {
extractEspresso();
addHotWater();
yield new Coffee("아메리카노");
}
case "카페라떼" -> {
extractEspresso();
steamMilk();
yield new Coffee("카페라떼");
}
default -> throw new IllegalArgumentException("없는 메뉴입니다.");
};
}
private void extractEspresso() {
System.out.println("약한 압력으로 에스프레소를 추출합니다.");
}
private void addHotWater() {
System.out.println("뜨거운 물을 넣습니다.");
}
private void steamMilk() {
System.out.println("우유를 데우고 거품을 냅니다.");
}
}
// 숙련된 바리스타
class SeniorBarista implements Barista {
@Override
public Coffee makeCoffee(String menuName) { // 다른 방식으로 구현된 메서드
return switch (menuName) {
case "아메리카노" -> {
adjustGrinder();
extractEspresso();
addHotWater();
yield new Coffee("아메리카노");
}
case "카페라떼" -> {
adjustGrinder();
extractEspresso();
steamMilkWithLatte();
yield new Coffee("카페라떼");
}
default -> throw new IllegalArgumentException("없는 메뉴입니다.");
};
}
private void adjustGrinder() {
System.out.println("원두 분쇄도를 조절합니다.");
}
private void extractEspresso() {
System.out.println("최적의 압력으로 에스프레소를 추출합니다.");
}
private void addHotWater() {
System.out.println("최적의 온도로 물을 넣습니다.");
}
private void steamMilkWithLatte() {
System.out.println("우유를 완벽한 온도로 데우고 라떼아트를 만듭니다.");
}
}
// 캐시어 클래스
class Cashier {
private final Barista barista;
public Cashier(Barista barista) {
this.barista = barista;
}
public Coffee orderCoffee(String menuName) {
// 바리스타에게 메시지를 보냄 (makeCoffee)
return barista.makeCoffee(menuName);
}
}
// 실행 예시
public class CafeExample {
public static void main(String[] args) {
// 초보 바리스타로 시작
Cashier cashier = new Cashier(new JuniorBarista());
cashier.orderCoffee("아메리카노"); // 메시지 전송
System.out.println("\n바리스타 교체\n");
// 숙련된 바리스타로 교체
cashier = new Cashier(new SeniorBarista());
cashier.orderCoffee("아메리카노"); // 동일한 메시지, 다른 처리 방식
}
}
- 앞서 설명한 메시지를 수신한 객체가 실행 시간에 메서드를 선택할 수 있다
- 메시지
makeCoffee(String menuName)
→ 커피 만들어 달라는 요청- 캐시어는 바리스타에게 단순히 메뉴 만들어달라는 메시지만 전달
- 캐시어는 어떻게 메뉴가 만들어질지 모름
- 메서드
JuniorBarista
와SeniorBarista
의makeCoffee
구현 부분- 각 바리스타가 커피를 만드는 구체적인 방법
- 같은 메시지에 대해 다른 방식으로 처리
객체지향의 본질
- 객체지향이란 자율적인 객체들을 이용해 시스템을 분할하는 방법이다
- 자율적인 객체란 상태와 행위를 함께 지니고 스스로 자기 자신을 책임지는 객체
- 객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 수신한 객체는 메시지 처리하는데 적합한 메서드를 자율적으로 선택
- 객체지향 → 클래스 라고 생각하지 말고 우선적으로 객체를 떠올리자
- 애플리케이션을 협력하는 객체들의 공동체가 아닌 클래스로 구성된 설계도로 보는 관점은 유연하고 확장 가능한 애플리케이션의 구축을 방해함
코드를 담는 클래스의 관점에서 메시지를 주고 받는 객체의 관점으로 사고의 중심을 전환하자
- 객체지향의 핵심은 클래스가 아니다 (물론 클래스도 중요함)
- 클래스는 객체를 만드는데 필요한 구현 메커니즘일 뿐..
- 메시지를 주고받는 객체들의 동적인 관계가 중요하다
클래스의 구조, 메서드에 집중하지 말고 객체의 역할, 책임, 협력에 집중하자
반응형