안녕하세요!
이번주는 회고록 대신 객체지향에 대한 포스팅을 해보려고 합니다!
사실.. 2주차 과제를 진행하면서 크게 배운 점이 없었던 거 같은 느낌이 너무 많이 들더라구요..
그래서 회고록을 적는 것보다는 프리코스 과정에서 공부했던 과정들을 여기에 담아보는게 더 좋을 것 같다는 생각이 들어서 당분간은 공부를 하는 과정들을 위주로 포스팅을 하려고 해요!
그런 의미로 나머지 주차에 대한 회고록은 프리코스가 끝난 뒤에 적어보려고 합니다!
물론 회고록도 중요하지만! 프리코스를 제출할 때마다 회고록을 함께 적어 제출을 하고 있거든요..
그래서 현재로써는 회고록을 두번 써가면서 나를 되돌아 보는 것보단 공부 과정들을 담아보려고해요 :)
00 시작하며..
오늘의 포스팅 주제는 "메세징"에 대한 이야기를 해볼까합니다.
벌써 프리코스 3주차라니.. 시간이 너무 빨리 흘러버렸네요..
이번주 과제를 시작하기 앞서 기능 설계를 우선적으로 하고 있는데요. 책임을 구분하며 역할을 나누고 있는데 약간 애매한 부분도 많고 막히는 부분이 생겨서 설계에 대한 공부를 조금 더 해야할 거 같다는 생각이 들더라구요.
그래서 최근에 프리코스를 시작하면서 "객체지향의 사실과 오해"라는 책을 읽기 시작했답니다.
음.. 근데.. 정말로... 너무 이해하기 힘든거있죠..😭
특히, 이 책에서는 메세지를 전송하여 다른 객체에게 책임을 위임해라라는 표현이 등장하는데 도대체 메세지를 전송하라는게 무슨 뜻인지 이해를 할 수 없더라구요....
메소드를 호출하라는 걸까..?라고 생각했지만.. 그러기엔 메세지 전송과 메소드를 호출한다는 것을 따로 구분하며 설명하는거 있죠..ㅠㅠ
그래서 오늘은 이 의미에 대해 정확히 파악해보려 이렇게 포스팅을 시작하게 되었답니다!
다들 저와 같은 고민이라면 함께 공부해보아요 !
01 메세징(메세지 전송)이란?
객체가 다른 객체에게 인터페이스를 요청하는 것을 의미합니다.
여기서 말하는 인터페이스는 자바에서 사용하는 인터페이스를 의미하는 것은 아니구요.
객체 간의 소통을 가능하게 해주는 public method라고 생각해주시면 좋을 거 같아요!
왜 메세징이 필요할까?
일반적으로 우리는 하나의 클래스에 모든 책임을 부여하지 않습니다. 왜냐하면 SOLID 규칙에서 SRP(단일책임원칙)에 어긋나기 때문이죠.
SRP는 하나의 클래스는 하나의 책임만 갖도록 한다라고 명시되어 있습니다. 그렇기 때문에 본인이 할 수 없는 책임을 다른 객체에게 요청해야만 해요!
그렇다면 메세지 전송은 어떻게 사용하는 걸까?
저도 이부분에 대해서 책으로만 읽으며 제대로 감이 오지 않아 구글링을 하며 찾아보았답니다 ㅎㅎ
책에서 메세지를 전송하여 다른 객체에게 요청하라라는 의미가 잘 와닿지 않았던 저는 클라이언트 클래스에 다른 객체(서버객체)를 호출하는 메소드를 새로 만들어야 한다는 의미인가? 단순히 서버 객체에 있는 메소드를 호출하면 된다는 의미인걸까? 라는 고민을 많이 해왔습니다.
결론적으로 말하자면 다른 객체에 있는 메소드를 호출하면 되는거지만 이는 잘못된 표현인거 같구요!
정확히 말하자면 "메세지 전송"을 한다는 표현이 맞다고 합니다:)
자바에서는 오퍼레이션 + 인자의 형태로 사용한다고 해요.
car.stop() // 자동차 정지
이런식으로 말이죠!
그러면 결국 다른 객체의 메소드를 호출한다고 생각하는게 맞지 않나? 라고 생각하실 수 있을 거 같은데요!
완.전.히 다른 표현이랍니다!
02 메세지 전송 vs 메소드 호출
예시를 하나 들어볼게요.
만약 메세지를 요청하는 클래스를 클라이언트 객체, 반대로 응답하는 객체를 서버객체라고 생각해봅시다.
클라이언트 객체에서 자동차를 정지하기 위해 car.stop()이라고 메세지를 전송하면 이는 Java Runtime System에서 메세지를 오퍼레이션으로 해석하게 됩니다. 이를 서버 객체에서 오퍼레이션에 맞는 정확한 메소드를 찾아 실행하는 것이지요!
그래서 책을 읽다보면 종종 이런 표현도 보이는데요!
"객체의 관점에서 자율성이란 자신의 상태를 직접 관리하고 상태를 기반으로 스스로 판단하고 행동할 수 있음을 의미한다."
라는 설명이 나오는데요. 이부분을 읽으며 어떻게 객체가 스스로 판단을 한다는거지?라는 의문을 갖고 있었답니다..
바로 그 의미가 이 예시에서 설명이 됩니다. 메세지를 통해 오퍼레이션으로 해석되어 이를 서버 객체에서 오퍼레이션에 맞는 정확한 메소드를 찾아 실행한다는 부분이 바로 객체가 자신의 상태를 기반으로 스스로 판단하여 행동하는 것을 의미하는 것을 말하는거랍니다!
이 부분을 이해하면서 얼마나 아차! 싶으면서도 얼마나 소름이던지.. 자바에 대한 이해가 아직은 많이 부족한가봐요 하하..😅
다시말해 메세지 전송이라는 것은 객체의 구체적인 메소드를 말하는 것이 아닌 인터페이스를 통해 추상적인 명령을 전달한다고 보면 되고, 메소드 호출은 Runtime에 오퍼레이션 호출에 의해 구현된 코드를 실행하는 것이라고 이해하시면 됩니다.
이렇게 메세지 전송과 메소드 호출을 구분함으로써 3가지의 이득이 생깁니다.
1. 메세지 전송자는 수신자가 실행하는 메소드가 어떻게 실행되는지 몰라도 된다. 단지 인터페이스의 이름만으로 무엇을 할 수 있는지 알 수 있고 명령을 내리면 된다.
2. 메세지 수신자는 누가 전송하는지 알 필요없고 전송받은 메세지에 대응하여 자체적인 처리를 결정할 수 있는 자율권을 얻는다.
3. 메세지 전송자와 수신자가 느슨하게 결합되도록 할 수 있다.
메소드가 어떻게 실행되는지 모르는 것이 왜 이득일까?
종종 이런 말을 들어봤을지 모르지만, 저는 자바를 배워오면서 "서로의 클래스가 각각의 역할을 모르게 해라"라는 이야기를 들어왔는데요!
한번 생각을 해볼게요! 저희가 백엔드와 프론트엔드로 구분을 하여 개발을 하는 과정에 있어서 해당 어플을 사용하는 클라이언트 입장에서는 저희가 개발한 과정에 대해 알지 못해도 만들어진 인터페이스만으로도 충분히 사용을 할 수가 있죠! 바로 UI라는 인터페이스를 통해서 무엇을 할 수 있는지 알 수 있고 버튼을 누르기만 하면 됩니다.
그래서 서버 객체에게 메세지만 전송한다면 나머지 책임에 대한 권한은 서버 객체에게 위임되는 것으로 보면 됩니다.
즉, "어떻게"보다는 "무엇을"하는지 행위에만 집중할 수 있도록 오퍼레이션명과 인자를 통해 의미를 전달만 해도 충분하다는 것이죠!
그래서 메세지 호출에 해당하는 메소드명을 지을 경우엔 일반적으로 "무엇을" 하는 지에 초점을 맞춘 명령형으로 짓는 것이 좋다고 해요!
메세지에 대응하여 자체적인 처리를 결정할 수 있는 자율권을 얻는다.
메세지 전송 이후는 서버 객체에게 모든 권한이 위임이 되는 것으로, 클라이언트 객체에서는 서버 객체가 어떻게 구현되었는지 알 수 없습니다. 예를 들어 cat.eat("사과"), dog.eat("바나나")라고 한다면 고양이는 사과를 먹고, 강아지는 바나나를 먹으라고 메세지를 보낼 수 있습니다.
서버 객체에서는 메세지를 받으면 메세지에 대응하여 자신이 가지고 있는 데이터를 이용하여 어떻게 처리할지 자율권을 얻게 되는 것이죠.
이러한 모델을 "행위자 모델(ActorMedel)"라고 합니다.
느슨한 결합이란?
이부분은 코드로 접근을 해보도록 할게요.
public interface Puppy{
public void drink(Water water);
}
public class Choco implements Puppy{
@Override
public void drink(Water water){;}
public void bark(){;}
}
public class Client{
public void Client(Choco choco, Water water){
choco.drink(water);
choco.bark();
}
}
이렇게 Client가 추상 클래스가 아닌 Choco라는 구체 클래스를 인자로 받아 처리를 하고 있습니다. 이 코드는 Client가 Choco의 변화에 매우 민감해질 수 밖에 없게 되죠. 왜냐하면 Choco라는 클래스가 사라질 수 있고, 이름이 변경될 수도 있습니다. 또한, bark()의 오퍼레이션명을 변경하거나 삭제가 될 수도 있죠..
이렇게 변화에 민감해지는 것을 강한 결합이라고 하고, 그 반대를 느슨한 결합이라고 합니다.
끝마치며..
객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야하고 어떤 객체로부터 메세지를 수신할 것인지 결정하는 것으로부터 시작된다
라는 부분을 읽으며 설계에 대한 방향성에 대해 다시한번 생각해보는 계기가 되었습니다.
2주간 프리코스를 진행하며 책임을 나누면서 책임을 구현하는 방법에 대한 고민까지 진행을 해왔었는데요. 설계를 하는데에 가장 먼저 생각할 부분이 어떤 책임이 필요한지 그 책임을 수행하는 객체가 어떤 메세지를 수행할 것인지에 대해 고민해보는 방향성이 정말 중요할 것 같다는 생각이 들었어요..
오늘 배운 개념들을 통해 각 객체 간에 어떤 메세지를 주고 받아야할지에 대해 먼저 고민해보고 구현을 해보는 방식으로 진행해보려구요!!
이번 3주차 과제는 더욱 성장한 설계와 코드로 탄생했으면..🙏🏻
이렇게 이번 포스팅도 마치도록 하겠습니다.
오늘도 긴 글 읽어주셔서 감사합니다 😙
📚 참고문헌
'Java' 카테고리의 다른 글
Refactoring은 극단적으로 해볼수록 더욱 성장한다 ! (feat. TDD) (0) | 2024.05.14 |
---|---|
[Java] Java Code Convention (1) | 2023.10.21 |