캡슐화란 무엇인가?

YunSeong Park·2022년 2월 6일
0

객체지향

목록 보기
1/1
post-thumbnail

공부한 내용을 정리한 글입니다.
비판적으로 읽으시고, 부족한 부분이 있다면 댓글로 알려주세요.

캡슐화란?

위키백과에서는 캡슐화를 다음과 같이 설명한다.

  • 객체의 속성(data fields)과 행위(메서드, methods)를 하나로 묶고,
  • 실제 구현 내용 일부를 내부에 감추어 은닉한다.

하지만 위 설명 만으로는 왜 객체의 속성과 행위를 묶어야 하는지, 왜 일부 내용을 은닉해야 하는지, 이를 통해 무엇을 달성하고자 하는지 이해하기 어렵다.

객체지향에서 캡슐화를 따름으로 어떤 이점을 가져갈 수 있을지 알아보자.

함께 두기 (Co-location)

Human이라는 data fields가 있고, 이를 인자로 받는 함수들이 있다고 하자

interface Human {
  name: string; 
  age: number;
  hunger: number;
}

function work(human: Human){
  human.age++; 
  human.hunger++;
}

function eat(human: Human) {
  human.hunger = 0;
}

지금은 Human을 사용하는 함수가 work()eat() 두 개뿐이다.

  1. 하지만 그 개수가 수십 개로 늘어나고,
  2. 그 함수들이 여러 파일에 흩어져있다면 어떤 일 이 발생할까?

Humaninterface를 수정하면 여러 파일을 돌아다니며 기존에 작성한 함수에 문제가 없는지 확인해야 한다.

이러한 문제를 해결하기 위해 정의된 interface함수들을 하나의 파일에서 관리할 수 있다.

예를 들면 human.ts 라는 파일을 만들고 interface함수들을 이 안에서 관리한다면, inteface를 수정하고 바로 같은 파일에서 다른 함수들을 확인하며 수정할 수 있다.

하지만, class를 이용하면 이를 data field함수들을 자연스럽게 함께 두며 관리할 수 있다.

class Human {
  name: string = 'yun seong';
  age: number = 28;
  hunger: number = 100;

  work(){
    this.age++;
    this.hunger++;
  }

  eat(){
    this.hunger = 0;
  }
  ...
}

완전히 책임지기(full responsibility)

class를 정의하여 data field함수들을 함께 둠으로써 코드의 유지보수성을 향상시켰다.

하지만, 이 정도로 충분할까?
상상력을 발휘해보자, 갑자기 화면에 출력되는 Humanage-10이 되었다면 우리는 어떻게 대처해야 할까?

  1. Human class를 확인하여 잘못된 로직이 있는지 확인한다.
  2. Human을 구현한 모든 코드를 확인하며, age를 -10으로 set한 코드를 찾는다.

위처럼 단순히 모아 놓기만 한 class를 사용했다면, Human 가져가 구현한 모든 코드를 확인해야 한다. 프로젝트가 커질수록 확인해야 할 코드의 양도 많아질 거다.

이를 어떻게 해결할 수 있을까?

class Human {
  private _name: string = 'yun seong';
  private _age: number = 28;
  private _hunger: number = 100;

  get name(){
    return this._name;
  }

  get age(){
    return this._age;
  }

  get hunger(){
    return this._hunger;
  }

  work(){
    this._age++;
    this._hunger++
  }

  eat(){
    this._hunger = 0;
  }
  ...
}

private 접근 제어자를 사용해 내부 data field를 직접적으로 수정할 수 없게 만들고 class 외부에서는 getter 함수를 통해 data field를 사용할 수 있다.

이를 통해 Human class에 관련된 문제가 발생했을 때, class를 정의한 코드만 확인해도 문제를 추적할 수 있도록 완전한 책임을 진다.

여기서 재밌는 부분은 완전한 책임구현체 단위로 적용되는 것이 아니라, class 단위로 적용된다는 것이다.

class Human{
 ...
 private _hunger = 100;

 feed(human: Human){
    human._hunger = 0
  } 
 ...
}

위에서 feed()가 다른 Human 구현체를 받아 _hunger를 수정한 것처럼, 같은 class의 구현체라면 서로 privatedata field에 접근하고 수정할 수 있다.

나는 이런 동작이 허용되는 이유가 feed()Human class 내부에서 정의되어있고, feed()로 인해 다른 구현체에 버그를 유발하더라도 Human class 내부에서 확인 가능하기 때문이라고 느꼈다.

결론

캡슐화는 data field와 이에 관련된 함수들을 함께 두고, 완전한 책임을 가짐으로, 버그 발생 시 해당 class를 정의한 code만 확인해도 버그를 추적할 수 있도록 해준다.

profile
Front-End developer

0개의 댓글