나는 '여우와 두루미' 예시를 참 좋아한다. 너무 오래되서 내용의 전체 줄거리는 기억이 안나지만 여우와 두루미가 자기만의 표현 방식으로 상대를 자신의 퍼즐에 끼워 맞추려고 했을 때, 서로 기분만 안좋아진다는 그런 내용 말이다.

이번에 회사에서 객체 지향에 대해서 설명하는 내 자신이 그러했다. 20분만에 담기 어려운 내용을 끼워 맞추려다 보니 더 어려웠다. 뭔가 블로그를 쓰는 이유도 이 스피치를 하는 이유도 상대방이 이해가 잘 되었으면 하는 바람이 있고, 무엇보다 소프트웨어 장인 정신에

"Not only individuals and interactions, but also a community of professionals"(개별적으로 협력하는 것 뿐만 아니라, 프로페셔널 커뮤니티를 조성하는 것을)

내용에 의거하여 쉽게 설명하여 수준을 높이는 일에 일조하고 싶었기 때문이다. 주관적이지만 쉽게 풀어 쓰고자 하지만 더 나은 표현이 있다면 도움을 주길 바란다.

아 그리고 나는 프론트엔드 개발자여서 Typescript, React 기준으로 설명을 하니 참고 바란다.


서론.

객체에 대해서 자신만의 주관이 있어야 한다.(객체는 @@다. 하는 주관.) 객체지향 프로그래밍을 처음 배웠을 때, 마치 현실 세계를 모방한 것과 같이 자신만의 주관이 필요하다. 그렇지 않으면 사실 객체란 무엇인가에 대해 의미론적으로만 배워가는 시간이 될 것이다.

나는 객체지향의 사실과 오해 : 역할, 책임, 협력 관점에서 본 객체지향에서 말하는 객체에 대해 설명하고자 한다. 여기서 가장 훌륭한 객체는 자율적인 객체 라는 표현이 있다. 자율적인 객체를 이해하기 전에 객체란 무엇인지에 대해 알아보자.

객체

흔히 객체는 **상태(state)**와 **행동(behavior)**을 함께 지닌 실체라고 정의한다. 현실 세계의 객체와 차이점이 있다면 객체는 스스로 상태를 관리한다는 것이다.

예를 들면, 물이 담긴 '물컵'이라는 객체에 물이 줄어들려면 '사람'에 의해서 '물을 마시거나', '물을 버리거나' 할 것이다. 이렇게 보면 현실 세계에선 사람이 물을 줄어들게 하지만, 객체 지향 세계에선 물컵이 물을 스스로 줄어들게 한다.

객체 세계로 들어가보자. 여기 간단하게 컵이 있다. 이 컵은 안에 내용 내용물이 얼마나 남아있는지만 확인하는 객체이다. 아래 코드를 보면서 객체의 상태와 행동이 무엇인지 알아보자.

class 물컵 {
  물양: number;
	constructor(담겨_있던_물양:number){
      this.물양 = 담겨_있던_물양;
 	}

  	// 물 얼마나 남았지?
	  getAmount() {
      return this.물양;
    }

  	// 물 줄이기
  	lossAmount(뺄_물양: number): void {
      this.물양 = this.물양 - 뺄_물양;
    }

  	// 물 늘리기
  	addAmount(더할_물양: number): void {
      this.물양 = this.물양 + 더할_물양;
    }
}

여기서 상태는 this.물양이며, 물컵에 담겨 있는 물의 양이다. 여기서 행동은 무엇일까? getAmount, lossAmount, addAmount이다. 우리는 이렇게 상태와 행동에 대해서 알아보았는데 객체는 이 상태와 행동을 함께 지닌 실체이다. 우린 저 코드 보면서 해당 행동들이 어떤 역할을 하는지 알고 있을 것이다. 자 이제 저 행동을 수행할 사람을 만들어보자.

class 사람 {
  이름: string;
	constructor(이름:string){
      this.이름 = 이름;
 	}

  	키미노_나마에와() {
      return console.log('나의 이름은 ', this.이름);
    }

  	물_젠부_쏟아버리기(cup: 물컵): void {
    	cup.lossAmount(cup.getAmount());
  	}

	물_마시기(cup: 물컵, amount: number): void {
    	cup.lossAmount(amount);
  	}

    물_채우기(cup: 물컵, amount: number): void {
      	cup.addAmount(amount);
    }
}

여기서 상태는 이름 밖에 없는 사람 클래스가 있다. 그러나 객체의 행동은 물컵과 연관이 되어있다. 이제 우리는 객체가 어떻게 연결되어 행동하는지 알아보자. 복사해서 확인하기 쉽도록 전체 코드를 넣었다.

class 물컵 {
  물양: number;
	constructor(담겨_있던_물양:number){
      this.물양 = 담겨_있던_물양;
 	}

  	// 물 얼마나 남았지?
	  getAmount() {
      return this.물양;
    }

  	// 물 줄이기
  	lossAmount(뺄_물양: number): void {
      this.물양 = this.물양 - 뺄_물양;
    }

  	// 물 늘리기
  	addAmount(더할_물양: number): void {
      this.물양 = this.물양 + 더할_물양;
    }
}

class 사람 {
  이름: string;
	constructor(이름:string){
      this.이름 = 이름;
 	}

  	키미노_나마에와() {
      return console.log('나의 이름은 ', this.이름);
    }

  	물_젠부_쏟아버리기(cup: 물컵): void {
    	cup.lossAmount(cup.getAmount());
  	}

	물_마시기(cup: 물컵, amount: number): void {
    	cup.lossAmount(amount);
  	}

    물_채우기(cup: 물컵, amount: number): void {
      	cup.addAmount(amount);
    }
}

// 스토리 텔링
console.log("물컵이라는 객체를 만들었다. 이 안에는 500ml의 물이 있다. (꽤 많이 들어가네..?)")
const myCup = new 물컵(500);

console.log("'노치'는 물을 엎지를거다 그러기 위해선 '노치'를 만들어야지.")
const nochi = new 사람("Nochi");

// 키미노_나마에와
nochi.키미노_나마에와()
console.log("물의 양: ", myCup.getAmount())

console.log("'노치'는 물을 전부 엎질러버린다.")
nochi.물_젠부_쏟아버리기(myCup)
console.log("물의 양: ", myCup.getAmount())

console.log("'노치'는 물은 알아서 마를테니 다시 물을 채운다.")
nochi.물_채우기(myCup, 300)
console.log("물의 양: ", myCup.getAmount())