OOP에는 inheritance, encapsulation, polymorphism, abstraction 이라는 네가지 핵심개념이 있습니다. Encapsulation도 이 핵심 개념 중 하나에 해당하는데요, 어떠한 의미일까요? 먼저 이름에서 느껴지다시피 무언가 안에 담아 두는 것 같다는 생각이 듭니다.
실제로 encapsulation은 class 내부의 variable(data)들을 method로 감싸서 variable과 method를 하나의 유닛으로 묶어주는 것입니다. 이렇게 되면 variable에 접근하기 위해서는 method를 통할 수 밖에 없게 됩니다. 하나의 유닛으로(capsule) variable를 감싸놓는 이유는 다른 클래스에서 variable에 즉, 데이터에 직접적으로 접근하는 것을 방지하기 위함입니다. 보호하고 싶은 데이터를 캡슐이라는 보호장치로 감싸준다고 생각하면 좋을 것 같습니다.
어떻게 외부에서의 접근을 막을 수 있을까요?
바로 variable의 access modifier(접근 제어자)를 private으로 설정해주는 겁니다.
그리고 해당 variable에 접근할 수 있는 setter와 getter등의 methods를 적절하게 사용하면 됩니다.
이름이 거창하게 느껴지지만 사실상 class를 배우면서 사용해오던 방식입니다.
Encapsulation을 사용하면 외부에서는 데이터가 어떻게 처리되는지 알 수가 없습니다. 캡슐 안에서 처리가 이루어지기 때문에 보이지 않는 것이죠. 이게 바로 encapsulation이 원하는 것입니다.
왜 다른 클래스에서 variable에 접근하는 것을 막아야 하는 걸까요?
1. 클래스 내부의 data를 외부에서 바로 접근할 수 있게되면, 원하지 않는 변경이 생길 수가 있습니다.
예를 들어서 Car class에 public으로 gas라는 field를 생성해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class Car {
//gas field를 pulic으로 선언
public int gas;
//사용 후 남은 gas 양을 알려주는 method
public void useGas(int gasUsed){
if(this.gas <= 0){
System.out.println("Out of gas.");
} else {
this.gas -= gasUsed;
if(this.gas > 0){
System.out.println("Gas remaining: " + this.gas);
} else {
System.out.println("Gas remaining: " + this.gas);
System.out.println("Out of gas.");
}
}
}
|
cs |
이렇게 public으로 선언한 field는 외부 class에서도 접근이 가능해집니다.
1
2
3
4
5
6
7
8
9
|
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.gas = 10;
}
}
|
cs |
이게 뭐가 문제가 되는 걸까요? 🤔
Car class에서 정의해주었던 useGas() method를 사용해서, 기름 사용량에 따라 얼마나 많은 기름이 남아있는지 알아보겠습니다. Line#5에서 기름을 10으로 셋팅해주고 line#6에서 기름을 9만큼 사용하였습니다.
그러면 10 - 9 연산을 Car class에 있는 useGas method가 연산한 뒤 1이라는 값을 줄 것입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.gas = 10;
car.useGas(9);
//Prints: Gas remaining: 1
System.out.println("-----------------");
car.gas = 100;
car.useGas(10);
//Prints: Gas remaining: 90
}
}
|
cs |
그런데 중간에 line#11에 car.gas = 100 가 끼어들었습니다. 그러면서 기름양이 1에서 100으로 변하게 되고, 10만큼 사용하여도 90이 남았다는 메세지를 보냅니다. car.gas = 100로 다시 값을 초기화하지 않았다면 Out of gas. 메세지를 보내왔을텐데 말입니다. 이런 식으로 encapsulation을 하지 않으면, field value 변경이 생길 위험이 있어 의도하지 않은 결과를 불러올 수 있게 됩니다.
추가적으로, instance 생성 시마다 매 필드에 접근하여 값을 부여하게되면 깜빡하고 initialize하지 않는 변수가 생길 가능성도 있습니다. 일일이 필드값을 설정해 주기보다는 constructor(생성자)를 만들어서 사용하면 누락의 가능성을 없앨 수 있습니다.
2. 재사용성이 높아집니다. (동시에 유지 보수가 용이해집니다.)
Car class에서 정의했던 useGas() method를 따로 만들어 두지 않는다면 어떨까요?
Object를 하나만들때 마다 같은 내용의 method를 main에 중복해서 만들어야 될겁니다. (useGas()과 같은 기능을 사용하기 위해서는요!) 중복해서 작성하게되는 method가 길어질 수록 실수의 위험도 커지며, 코드가 전체적으로 길어지고 복잡해져서 가독성도 매우 떨어질 것입니다. 하지만 기능을 수행해주는 method를 해당하는 class 안에 정의하고, 연산이나 모든 프로세스가 그 안에서 이루어지게 만든다면 이와 같은 문제가 현저히 줄어들게 됩니다. 사용자는 그저 class 에서 제공하는 함수만 불러서 사용하면 끝인것이죠. 유사한 코드를 중복해서 작성할 필요가 없기 때문입니다.
이렇게 코드 재사용성이 높아지면 사용이 훨씬 편리하기도 하고, 수정사항이 있을 때 해당 메서드만 수정하면 되므로 유지 보수가 용이해집니다.
한 번 예시를 보겠습니다. Car class에서 public으로 만들었던 gas를 private으로 먼저 변경하였습니다. 그리고 constructor를 사용해서 Main class에서 car class object를 하나 만들었습니다. 그런 다음 useGas() method를 사용하였습니다.
1
2
3
4
5
6
7
8
9
|
public class Main {
public static void main(String[] args) {
Car car = new Car(10,"volvo","engine","white");
car.useGas(5);
}
}
|
cs |
그런데 Car.java 파일로 돌아가서 다시 생각해보니 gas라는 말보다는 gasoline이 더 정확한 것 같아 필드명을 바꾸고 싶어졌습니다.
1
2
3
4
5
6
7
8
9
10
|
public class Car {
//private int gas;
private int gasoline;
//...
}
|
cs |
이런식으로 Class 내부에 변경사항이 생겨도 car object는 아무런 변경을 해줄 필요가 없습니다.(물론 method의 이름이 바뀌는 경우는 좀 다르겠죠? method는 외부에서 직접 사용하는 것이니까요.) 이렇듯 encapsulation을 통해 클래스 내부에서 일어나는 변화를 외부에서는 알지 못하게 하는 것이 어떠한 편리함을 가지고 오는 지 한번 더 확인할 수 있었습니다.
지금까지 캡슐화의 중요성에 대해 알아보면서 사용법에 대해 더욱 잘 알게되어 활용에 도움을 많이 받을 것 같습니다. ☺️
*참고자료:
https://www.tutorialspoint.com/java/java_encapsulation.htm
https://www.geeksforgeeks.org/encapsulation-in-java/
'Java' 카테고리의 다른 글
Class(7)-Up-casting & Down-casting (형변환 업캐스팅, 다운캐스팅) (2) | 2022.05.01 |
---|---|
Class(6)-Polymorphism(다형성) (0) | 2022.04.29 |
Class(4)-Composition (2) | 2022.04.27 |
Class(3)-Inheritance(상속) 사용하기 (0) | 2022.04.25 |
Class(2)-Constructor-set을 간편하게 (4) | 2022.04.25 |