1장에서는 객체란 무엇인지, 역할, 책임, 협력에 관해 우리의 있을 법한 일상생활을 예로들며 설명을 하는 내용을 담고있다.
1. 협력하는 객체들의 공동체
- 21p. 추상화 : 방화벽이 화재의 확산을 막는 것이 아니라 네트워크 침입을 막는다고 해서 문제될 것이 있는가??
- 해당 구문에서 어떠한 객체를 설계 한다는 가정하에, 항상 그 객체의 역할을 생각해보며 추상화 하는 시간을 가져야 한다는 것을 느꼈다. 방화벽이란 : "방화" 화재를 막는다는 의미의 단어이지만, 해당 단어의 역할 및 책임은 "막다" 이므로 문제될 것이 없다.
- 21p. 객체지향의 목표는 실세계를 모방하는 것이 아닌 새로운 세계를 창조하는 것(고객과 사용자를 만족시킬 수 있는 세계).
- 27p. 역할과 책임 : 객체들은 다른 객체와 협력하는 과정에서 특정할 역할을 부여 받는다.
객체의 역할이란
어떤 협력에 참여하는 특정한 사람이 협력 안에서 차지하는 책임이나 임무를 의미한다.
카페를 예로 들자면 손님이란 역할을 맡은 객체는 '커피를 주문한다.' 라는 책임이 존재하며, 학교를 예로 들자면 학생이란 역할을 맡은 객체는 '공부한다'. 라는 책임이 존재하는 것이다.
책에서는 카페를 예로들어 각 객체들이 어떻게 협력하고, 시스템 설계에서 궁극적으로 가진 목표에 대해서 객체들이 어떠한 역할을 맡아 각자의 책임을 다하는지 설명해준다.
책에서 나오는 역할은 손님,바리스타, 캐시어가 있다.
이들의 관계에 대해서 글과 함께 코드 예제로 살펴보겠다.
Cafe에서 Customer의 역할은 손님이다. 주문할 책임을 가진다.
public class Customer {
// 생략...
// 역할 : 손님
// 책임 : 커피를 주문
public String order (String menuName) {
return menuName;
}
}
Cashier의 역할은 손님의 주문을 받아서 바리스타에게 주문 내역을 요청할 책임을 가진다.
public class Cashier {
// 생략...
// 역할 : 캐셔
// 책임 : 주문을 받아 바리스타에게 알려준다.
public String takeOrder(Barista barista, String menuName) {
return barista.makeCoffee(menuName)
.orElse("없음");
}
}
Barista의 역할은 주문내역에 맞게 음료를 제공하고 다 만든 음료를 캐셔에게 전달한 책임을 가진다.
public class Barista {
// 생략...
// 역할 : 바리스타
// 책임 : 해당 메뉴를 검토하고 어떻게 만들지 정한다.
private List<String> recipe = new ArrayList<>();
public Optional<String> makeCoffee(String requiredMenu) {
return recipe.stream()
.filter(menu -> menu.contains(requiredMenu))
.findFirst();
}
}
이제 해당 객체들이 궁극적인 목표(주문을 받고 주문내역을 바탕으로 커피를 만들어서 손님한테 전달 하는 시스템)를 어떻게 향해 협력하는지 살펴보겠다.
public class CafeMain {
public static void main(String[] args) {
Customer customer = new Customer();
Cashier cashier = new Cashier();
Barista barista = new Barista();
String requiredCoffee = customer.order("아아");
String coffee = cashier.takeOrder(barista,requiredCoffee);
}
}
손님은 주문을하고 캐시어는 주문 내역을 통해 바리스타에게 전달한 후 바리스타가 준 커피를 받고 손님에게 전달해주면 끝난다.
내부적으로 어떠한 일들이 일어나는지 손님입장에서는 잘 모르고, 캐시어입장에서는 바리스타가 커피를 어떻게 만들어주는 지 모른다.
그리고 바리스타는 자기가 만든 커피가 누구한테 가는건지 모른다.
서로가 서로의 책임에 간섭하지 않고, 역할에 맡게 책임을 다하고 있다고 생각한다.
그리고 역할이란 책임을 암시한다.
역할이라함은 여러가지 조건이 존재한다.
- 여러사람이 동일한 역할을 수행할 수 있다.(즉 역할은 대체 가능하다는 것이다.)
-> 손님 입장에서 자신이 주문한 커피를 마실 수만 있다면 어떤 캐셔가 주문을 받는지는 중요치 않다.
손님 입장에서는 자신이 전달한 주문 내역에 맞게 커피를 받을 수 있다면 어떠한 바리스타가 커피를 제조하던 어떠한 캐셔가 주문을 받든 크게 상관없다.
Cashier 라는 인터페이스를 만들고 이를 구현한 클래스 NewPartTimer가 있고 해당 객체가 Cashier의 역할을 수행할 수 있다면 아무런 문제가 되지 않는다.
public class NewPartTimer implements Cashier{
@Override
public String takeOrder(Barista barista, String menuName) {
return barista.makeCoffee(menuName)
.orElse("없음");
}
}
Barista의 역할을 수행할 인터페이스를 만들고 이를 구현한 NewPartTimer2가 Barista의 역할에 맞는 책임을 수행 할 수 있다면 아무런 문제가 되지 않는다.
public class NewPartTimer2 implements Barista {
private List<String> recipe = new ArrayList<>();
public Optional<String> makeCoffee(String requiredMenu) {
System.out.println(requiredMenu + "에 대해서 잘 모르지만 만들어 볼게요");
return recipe.stream()
.filter(menu -> menu.contains(requiredMenu))
.findFirst();
}
}
- 책임을 수행하는 방법은 자율적으로 선택할 수 있다.
-> 요청을 받은 객체는 해당 요청 처리 방법을 자유롭게 선택할 수 있다.
예를 들어 카페에서 카푸치노를 요청했는데 어떤 바리스타는 카푸치노의 거품을 이용해 별표를 만들 수 있고, 어떤 바리스타는 하트를 만들 수 있는 것처럼 자신에게 들어온 요청을 수행하는 방식은 자율적이란 것이다.
여기 Barista의 역할을 수행할 수 있는 ProfessinalBarista와 NewPartTimer2가 있다.
해당 객체는 자신의 역할에 맞는 책임을 수행하면서 자신의 방법, 자율적으로 메서드를 처리한다.예) 시럽 추가.
public class ProfessianlBarista implements Barista{
private List<String> realRecipe = new ArrayList<>();
@Override
public Optional<String> makeCoffee(String requiredMenu) {
return realRecipe.stream()
.filter(menu -> menu.contains(requiredMenu))
.map(menu -> menu + "시럽추가")
.findFirst();
}
}
public class NewPartTimer2 implements Barista {
private List<String> recipe = new ArrayList<>();
public Optional<String> makeCoffee(String requiredMenu) {
return recipe.stream()
.filter(menu -> menu.contains(requiredMenu))
.findFirst();
}
}
NewPartTimer2는 일반적인 방식으로 만든다.
다형성을 활용한 방식이다.
public class CafeMain {
public static void main(String[] args) {
Customer customer = new Customer();
Cashier newPartTimer = new NewPartTimer();
Barista proBarista = new ProfessinalBarista();
String requiredCoffee = customer.order("아아");
String coffee = newPartTimer.takeOrder(proBarista,requiredCoffee);
System.out.println(coffee);
}
}
newPartTimer라는 캐시어는 proBarista에게 요청된 커피를 넘긴다.
- 한 사람이 동시에 여러 역할을 수행할 수 있다(즉 한 객체가 여러 책임을 가질 수도 있다는 것).
-> 한 사람이 캐시어의 역할과 바리스타의 역할을 동시에 수행하는 것도 가능하면서,
현실 속에 살아가는 우리 또한 회사에서는 회사원, 학교에서는 학생, 카페에서는 손님의 역할을 수행 하는 것이다.
Customer는 카페에서는 주문을 하는 손님이지만, 회사에 가면 다시 업무를 보는 회사원이다.
public class Customer extends Employee {
public String order(String menuName) {
return menuName;
}
@Override
public void doWorking() {
System.out.println("업무 보기");
}
}
협력하는 객체들(협력의 핵심)
객체들은 어떠한 특정 목표를 이루기 위해 서로 협력한다. 예) 커피 주문
협력의 핵심은 특정한 책임을 수행하는 역할들 간의 연쇄적인 요청과 응답을 통해 목표를 달성하는 것.
객체지향 설계라는 것은 적절한 객체(역할)에게 적절한 책임을 할당하는 것에서 시작된다.
책임은 객체지향 설계의 품질을 결정하는 가장 중요한 요소이면서, 책임이 불분명한 객체는 애플리케이션의 미래 역시 불분명하게 만든다.
얼마나 적절한 책임을 선택하느냐가 애플리케이션의 품질을 결정한다.
협력하는 '객체'의 조건
크게 2가지를 갖춰야 '객체'라고 부를 수 있다.
- 객체는 충분히 협력적이여야 한다. -> 다른 객체의 요청에 자신의 책임을 다 할 수 있어야 되고(요청에 적절히 자신의 역할에 맞는 책임을 완수하는 것), 다른 객체에게 적극적으로 도움을 요청할 수 있어야 한다.
- 객체는 충분히 자율적이여야 한다. -> 자기 스스로의 원칙에 따라 어떤 일을 하거나 자기 스스로를 통제하여 절제하는 것을 뜻한다.
예를 들어 다른 객체로부터 요청이 들어왔다고 해서 무조건적인 응답을 하는 것이 아니라, 응답을 할 지 말 지에 대한 결정마저 객체에게 존재한다는 것이다.
요청에 대해 스스로 판단하고 행동하는 자율적인 존재 라는 것.
위에 코드예제에서 proBarista는 자신의 방식으로 커피를 자율적으로 만들 수 있다.
상태와 행동을 함께 지닌 자율 적인 객체
객체는 상태와, 행동이 함께 지닌 실체이다.
객체가 자신의 역할을 부여받고, 행동을 가지고 협력에 참여하게 된다면, 그 행동을 하는데 있어서 필요한 상태도 함께 가지고 있어야 된다는 것이다.
Customer 객체는 자신이 주문을 했다면, 자신이 주문한 커피의 이름을 알고 있어야 받을 때에도 자신이 주문한 것이 맞는지 아닌지 알 수 있다.
public class Customer extends Employee {
private String orderHistory;
public String order(String menuName) {
orderHistory = menuName;
return menuName;
}
public void checkMyMenu(String menu) {
if (menu.equals(orderHistory)) {
System.out.println("감사합니다.");
} else {
System.out.println("저의 것이 아닙니다.");
}
}
@Override
public void doWorking() {
System.out.println("업무 보기");
}
}
커피를 제조하는 바리스타가 제조 방법을 모른다는 것이 말이 되지 않는다. 초밥집의 일식 요리사가 초밥을 만드는 법을 모르는 것이 말이 안되며, 자동차 정비소의 정비사가 자동차를 정비하는 방법을 모르는 것은 말이 되지 않는다.
public class ProfessionalBarista implements Barista{
private List<String> realRecipe = new ArrayList<>();
// 생략...
@Override
public Optional<String> makeCoffee(String requiredMenu) {
return realRecipe.stream()
.filter(menu -> menu.contains(requiredMenu))
.map(menu -> menu + "시럽추가")
.findFirst();
}
}
ProfessionalBarista객체는 realRecipe로 커피를 어떻게 만드는지에 대한 방법을 숙지하고 있다.
객체가 협력에 참여하는 과정 속에서 스스로 판단하고 스스로 결정하는 자율적인 존재로 남기 위해서는 필요한 행동과 상태를 함께 지니고 있어야 한다.
따라서 객체란 상태와 행위를 하나의 단위로 묶는 자율적인 존재이다.
자율적인 객체로 구성된 공동체는 유지 보수가 쉽고, 재사용이 용이한 시스템을 구축할 수 있는 가능성을 제시한다.
-> 위의 ProfessionalBarista
은 자신의 상태로 커피를 만드는 방법에 대한 recipe에 대해서 알고있다.
메서드와 자율성
객체는 다른 객체와 협력하기 위해 메시지를 전송하는데 수신자는 먼저 요청이 들어온 메시지를 이해할 수 있는지 여부를 판단 후 미리 정해진 자신만의 방법에 따라책임을 다한다.(메시지를 처리한다.) 이처럼 객체가 수신된 메시지를 처리하는 방법을 메서드라고한다.
그리고 메시지를 수신한 객체가 실행 시간에 메서드를 선택할 수 있다는 점은 다른 프로그래밍 언어와 객체지향 프로그래밍 언어를 구분 짓는 핵심적인 특징 중 하나이다.
public class NewPartTimer implements Cashier{
@Override
public String takeOrder(Barista barista, String menuName) {
String result = "";
if (barista instanceof ProfessionalBarista professionalBarista) {
result = professionalBarista.makeCoffee(menuName)
.orElse(professionalBarista.refuse());
}
if (barista instanceof NewPartTimer2 newPartTimer2) {
result = newPartTimer2.makeCoffee(menuName)
.orElse(newPartTimer2.refuse());
}
return result;
}
}
Cashier의 역할을 수행하는 NewPartTimer가 현재 출근 상태인 Barista에 따라 누구한테 주문을 맡길지 동적으로 결정한다.
객체지향의 본질
- 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할 하는 것.
- 자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 것.
- 객체지향은 시스템의 행위(해당 시스템의 역할 및 책임)를 구현하기 위해 다른 객체와 협력하는 것.
- 객체는 다른 객체와 협력하기 위해 메시지를 주고받는데, 요청 받은 메시지를 처리할 메서드를 자율적으로 선택할 수 있다는 것.
객체지향 시스템의 개발 시 좋은 개발을 하기 위한 노력
코드를 담는 클래스의 관점에서 메시지를 주고 받는 객체의 관점으로 사고의 중심을 전환 하는 것!!!
중요한 것은 어떤 클래스가 필요한가가 아니라 어떤 객체들이 어떤 메시지를 주고받으며 협력하는 가이다.
객체지향 설계의 핵심
- 적절한 책임을 수행하는 역할들 간의 유연하고 견고한 협력관계를 구축하는 것이다.
- 협력 구조와 책임을 식별하는 것이 중요하다.
- 객체지향은 객체를 지향하는 것이 중요하지 클래스를 지향하는 것이 아니다.
정리
1장의 내용은 현대사회에서 일어나는 사람들의 직업을가지고 협력을 어떻게 해나가는지에 대해서 설명해준다.
예를든 내용이 손님이 카페에가서 주문을하고 커피를 받기까지의 협력내용을 말하며, 객체지향에서의 추상화와 비슷한 구절들의 내용을 말해준다.
위에 예제코드로 보았듯이 역할이란 언제든지 대체 가능해야하며, 손님은 카페를 나가서 다시 회사에 가는 순간 회사원으로써의 역할을 부여받고 자신의 책임을 다한다.
1장의 내용을 읽으면서 객체지향적인 코드를 어떻게 작성해야하는지, 객체간의 협력은 어떻게 이루어지며, 역할과 책임은 어떻게 분배해야하는지에 대해서 많은 생각을 하게 되는 챕터였다.
역할 : 책임 혹은 의무를 뜻함
역할은 대체되어질 수 있어야한다. 책임을 수행하는 방법은 자율적이여야 한다.
한 객체가 여러가지의 역할을 수행할 수도 있어야 한다. -> 카페에서는 손님 회사에서는 회사원
협력 : 특정한 책임을 수행하는 역할들 간의 연쇄적인 요청과 응답을 통해 목표를 달성하는 것.
책임 : 해당 객체가 주어진 역할에서 수행해야하는 의무.
객체란 상태와 행위를 하나의 단위로 묶는 자율적인 존재이다.
자율적인 객체로 구성된 공동체는 유지 보수가 쉽고, 재사용이 용이한 시스템을 구축할 수 있는 가능성을 제시한다.
메서드 : 객체가 수신된 메세지를 처리하는 방법.
'북 스터디 > 객체지향의 사실과 오해' 카테고리의 다른 글
[Book] 6.객체 지도 (0) | 2024.06.20 |
---|---|
[Book] 5.책임과 메시지 (0) | 2024.06.20 |
[Book] 4.역할, 책임, 협력 (1) | 2024.06.13 |
[Book] 3. 타입과 추상화 (0) | 2024.06.13 |
[Book] 2. 이상한 나라의 객체 (0) | 2024.06.12 |