본 포스팅은 조영호님의 『객체지향의 사실과 오해 - 역할, 책임, 협력 관점에서 본 객체지향』 를 읽고 정리한 내용으로, 본문에 서적의 내용을 포함하고 있습니다❗️
객체지향 프로그래밍 / Object-oriented Programming(OOP):
'역할'과 '책임'을 수행하며 '협력'하는 객체들로 기능을 구현하는 프로그래밍 패러다임을 말한다.
목표는 객체들의 협력을 통해 달성되며, 목표는 더 작은 책임으로 분할되고 책임을 수행할 수 있는 적절한 역할을 가진 객체의 의해 수행된다.
협력에 참여하는 각 객체는 책임을 수행하기 위해 다른 객체에게 도움을 요청하기도 하며, 이를 통해 연쇄적인 요청과 응답으로 구성되는 협력 관계가 완성된다.
첫번째, 클래스가 아니라 객체를 바라보기
두번째, 객체를 독립적인 존재가 아니라 기능을 구현하기 위해 협력하는 공동체의 존재로 바라보기
세번째, 협력에 참여하는 객체들에게 적절한 역할과 책임을 부여하기
네번째, 위에서 설명한 개념들을 사용하는 프로그래밍 언어라는 틀에 흐트러짐 없이 담아낼 수 있는 기술 익히기
"객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메세지를 수신할 것인지를 결정하는 것으로부터 시작된다. 어떤 클래스가 필요하고 어떤 메서드를 포함해야 하는지를 결정하는 것은 책임과 메시지에 대한 대략적인 윤곽을 잡은 후에 시작해도 늦지 않다."
"역할"은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다. 협력 안에서 역할은 "이 자리는 해당 역할을 수행할 수 있는 어떤 객체라도 대신할 수 있습니다"라고 말하는 것과 같다.
결국 동일한 역할을 수행할 수 있다는 것은, 해당 객체들이 협력 내에서 동일한 책임의 집합을 수행할 수 있다는 것을 의미한다. 역할의 개념을 사용하면 유사한 협력을 추상화해서 인지 과부하를 줄일 수 있다. 그리고 다양한 객체들이 협력에 참여할 수 있게 되면서 협력이 좀 더 유연해지며 재사용성이 높아진다. 역할은 객체지향 설계의 단순성, 유연성, 재사용성을 뒷받침한다.
올바른 객체를 설계하기 위해서는 먼저 견고하고 깔끔한 "협력"을 설계해야 한다. 협력을 설계한다는 것은 설계에 참여하는 객체들이 주고받을 요청과 응답의 흐름을 결정한다는 것을 의미한다. 이렇게 결정된 요청과 응답의 흐름은 객체가 협력에 참여하기 위해 수행될 "책임"이 된다.
객체에게 책임을 할당하고 나면 책임은 객체가 외부에 제공하게 될 "행동"이 된다. 협력이라는 문맥에서 객체가 수행하게 될 적절한 책임, 즉 행동을 결정한 후에 그 행동을 수행하는 데 필요한 데이터를 고민해야 한다. 그리고 객체가 협력에 참여하기 위해 필요한 데이터와 행동이 어느 정도 결정된 후에 클래스의 구현 방법을 결정해야 한다.
결과적으로 클래스와 데이터는 협력과 책임의 집합이 결정된 후에야 무대 위에 등장할 수 있다.
객체가 존재하는 이유는 행위를 수행하며 협력에 참여하게 위해서다. 따라서 실제로 중요한 것은 객체의 행동, 즉 "책임"이다.
객체지향 패러다임이 강력한 이유는 "다형성"을 이용해 협력을 유연하게 만들 수 있기 때문이다.
다형성이란, 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다른게 반응하는 것을 의미한다. 좀 더 구체적으로 말해 '서로 다른 타입에 속하는 객체들이 동일한 메시지를 수신할 경우 서로 다른 메서드를 이용해 메시지를 처리할 수 있는 메커니즘'을 가리킨다.
다형성은 객체들의 대체 가능성을 이용해 설계를 유연하고 재사용 가능하게 만든다.
이러한 설계가 모두 다형성의 축복같지만, 사실 이 모든 것은 다형성을 지탱하는 메시지가 존재하기 때문에 가능한 것이다. 메시지는 송신자와 수신자 사이의 결합도를 낮춤으로써 설계를 유연하고, 확장 가능하고, 재사용 가능하게 만든다. 따라서 설계의 품질을 높이려면 훌륭한 메시지를 선택해야 한다.
핵심은 메시지가 "어떻게(how)"해야 하는 지를 지시하지 말고 "무엇(what)"을 해야 하는지를 요청해야한다. "어떻게"에서 "무엇"으로 전환하는 것은 객체 인터페이스의 크기를 급격하게 감소시켜 외부에서 해당 객체에게 의존해야 하는 부분이 적어지는 것을 의미한다. 결과적으로는 메시지 송신자와 수신자 간의 결합도가 낮아져 설계를 좀 더 유연하게 만들 여지가 많아지고, 의도 역시 명확해진다.
객체지향 설계의 중심에는 메시지가 위치한다. 객체지향 패러다임으로의 전환은 시스템을 메시지를 주고받는 동적인 객체들의 집합으로 바라보는 것에서 시작된다. 메시지를 주고 받는 객체들 사이의 커뮤니케이션에 초점을 맞춰라.
메세지중심 설계는 객체를 자율적으로 만들고 캡슐화를 보장하며 결합도를 낮게 유지시켜 주기 때문에 설계를 유연하게 만든다. 따라서 객체지향의 강력함은 객체들이 주고받는 메시지로부터 나온다.
자바스크립트가 유연한 언어인만큼,
자바스크립트로 객체를 표현하는 방식에는 다양한 방법이 있다.
가장 직관적이지만,
동일한 유형의 객체를 만들어야 하는 경우 중복발생 가능성이 크고,
메모리 사용하는 차원에서는 효율이 떨어진다.
new
키워드로 객체 인스턴스 생성하기.
객체를 '동적'으로 생성하는 방법.
하지만 여전히 같은 코드가 메모리 여기저기에 저장되는 문제가 있다.
dico를 브라우저에서 확인해보면 아래와 같이 보여진다.
생성자들이 모두 prototype이라는 객체를 가지고 있는데,
prototype 안에 메소드를 두면은 같은 지점의 메소드를 바라보게 되기 때문에 매번 같은 메소드를 새로 저장할 필요가 없다.
즉, 같은 prototype을 공유하며 prototype이 저장된 같은 메모리 공간을 공유한다.
메모리 효율성이 좋다!
브라우저에서 prototype 객체(__proto__
)를 열어보면 두 인스턴스 모두 showTime 메소드를 가지고 있는 걸 확인할 수 있다.
prototype이라는 키워드를 사용하지는 않지만
prototype객체를 만드는 방법과 동일하다고 볼 수 있다.
Class를 new
키워드로 호출하면 constructor
가 자동호출 되고,
constructor
는 객체 인스턴스를 만들어서 반환해준다.
Class역시 내부적으로 prototype을 사용하고 있다고 볼 수 있다.
ES6부터는 extends
키워드를 사용해서 다른 객체의 메소드를 상속받는 것이 가능해졌다.
예를 들어 아래와 같이 Sunshine
이라는 생성자함수가 있을 때,
Sunshine
의 모든 기존 메소드를 상속받는 Awake
라는 인스턴스를 새롭게 만들고 싶다면,
아래와 같이 한다.
*본 포스팅은 아래 도서를 참고 및 인용하여 작성되었습니다.
학습단계로 잘못된 정보가 있을 수 있습니다. 잘못된 부분에 대해 알려주시면 곧바로 정정하도록 하겠습니다 😊
조영호, 『객체지향의 사실과 오해 - 역할, 책임, 협력 관점에서 본 객체지향』, 유키북스(2015)
좋은글 감사합니다 ㅎㅎ