공부한 내용을 정리한 글입니다.
비판적으로 읽으시고, 부족한 부분이 있다면 댓글로 알려주세요.
위키백과에서는 캡슐화를 다음과 같이 설명한다.
하지만 위 설명 만으로는 왜 객체의 속성과 행위를 묶어야 하는지, 왜 일부 내용을 은닉해야 하는지, 이를 통해 무엇을 달성하고자 하는지 이해하기 어렵다.
객체지향에서 캡슐화를 따름으로 어떤 이점을 가져갈 수 있을지 알아보자.
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()
두 개뿐이다.
Human의 interface
를 수정하면 여러 파일을 돌아다니며 기존에 작성한 함수에 문제가 없는지 확인해야 한다.
이러한 문제를 해결하기 위해 정의된 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;
}
...
}
class
를 정의하여 data field
와 함수들
을 함께 둠으로써 코드의 유지보수성을 향상시켰다.
하지만, 이 정도로 충분할까?
상상력을 발휘해보자, 갑자기 화면에 출력되는 Human
의 age
가 -10
이 되었다면 우리는 어떻게 대처해야 할까?
위처럼 단순히 모아 놓기만 한 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
의 구현체라면 서로 private
한 data field
에 접근하고 수정할 수 있다.
나는 이런 동작이 허용되는 이유가 feed()
는 Human class
내부에서 정의되어있고, feed()
로 인해 다른 구현체에 버그를 유발하더라도 Human class
내부에서 확인 가능하기 때문이라고 느꼈다.
캡슐화는 data field
와 이에 관련된 함수들
을 함께 두고, 완전한 책임
을 가짐으로, 버그 발생 시 해당 class
를 정의한 code만 확인해도 버그를 추적할 수 있도록 해준다.