본문 바로가기

개발/JAVA객체지향디자인패턴

[JAVA객체지향디자인패턴] 캡슐화(Encapsulation) 란 무엇인가?

캡슐화(Encapsulation) 란 무엇인가?


캡슐화의 정의를 보면 필요한 속성(Attribute) 와 행위(Method) 를 하나로 묶고
그중 일부를 외부에서 사용하지 못하도록 은닉한다 되어있다.

위 내용만 보면 굉장히 추상적이라 뭘 어떻게 하라고 하는지 이해하기 힘들다 
따라서 간단한 예를 들어서 캡슐화를 이해해보도록 하겠다.

음료수자판기가 있다고 예를 든다
위의 정의를 따라가보도록 하겠다.

우선 필요한 속성(Attribute) 와 행위(Method)를 묶는다고 하였는데
그렇다면 음료수 자판기에는 어떠한 속성과 행위가있을까

예를 위해 간단하게 구현해보도록 하겠다.

속성(Attribute) 을 먼저살펴보면
속성은 자판기에 필요한 자료를 추려내면 될것이다.
1) 음료수목록
2) 음료수의가격
3) 사용자가 선택한 음료수
4) 사용자가 투입한금액 

행위(Method) 에는 
자판기내부적으로 일어나느 행위 그리고 외부적으로 보이는 행위 모두를 포함한다.
1) 해당음료수가 있는지 확인
2) 잔액확인
3) 음료수 가져오기
4) 잔액 반환

실제로 구현할때는 더 많은 속성과 기능들이 포함되지만 여기서는 이정도로만 정의하였다.

먼저 캡슐화를 하지 않은 코드를 살펴보겠다.


public class Student{
	
public class VendingMachine {
	
	public String drinks[] = {"콜라","사이다","환타"}; //음료수목록
	public int price; //가격
	public String drink; //선택한음료수
	public int amt; //투입금액
	
	 
	VendingMachine(int amt){ 
		this.amt = amt; 
	}
	
	public boolean isEmpty(int num){ //해당음료수가 있는지 확인 
		return drinks.length < num;
	}
	
	public boolean checkingBlance(){ //잔액환인
		return amt >= price;
	}

	public String getDrink(int num){ //음료수 가져오기 

		if( isEmpty(num) ){
			return "Drink get Fail";
		}
		
		drink = drinks[num];
		
		if( drink == "콜라" ){
			price = 1000;
		}else if( drink == "사이다" ){
			price = 900;
		}else if( drink == "환타" ){
			price = 800;
		} 
		
		if(!checkingBlance()){
			System.out.println("잔액부족");
			return "잔액: "+getBanlance();
		}
		amt = amt - price;
		return drink+"를 받는다.";
	}
	
	public int getBanlance(){//현재남아있는 잔액을 가져오고 금액 0원으로 초기화
		int temp = amt;
		amt = 0;
		return temp;
	} 
	
}


위 클래스는 캡슐화를 하지않았다.

모든 속성과 행위가 외부로 공개되어있다.


그렇다면 이를 실행하는 Client 클래스에서는 아래와 같이 구현한다.



public class VendingMachineClient {
	
	public static void main(String[] args){
		
		VendingMachine vm = new VendingMachine(2000); //2000원입력
		
		String[]drinks = {"콜라","사이다","환타"};
		vm.drinks = drinks;
		
		System.out.println(vm.getDrink(1));//콜라를 가져온다.
		System.out.println(vm.getDrink(2));//사이다를 가져온다.
		
		System.out.println(vm.getBanlance());//사이다를 가져온다.
		
		
	}
}


위에서 모든속성과 행위를 public 으로 선언하였기때문에 이와같이 모든 객체에 접근이 가능하다.

물론 위와같이 구현할수도 있겠지만 위와같이 구현하였을경우 몇가지 문제가 생긴다.


개발자마다 자판기 클래스를 호출해서 사용한다고 생각하자.

그렇다면 위와같이 자판기 클래스를 호출하여 음료수 목록을 정해주게 되는데 


만약 음료수를 추가하였다고 가정한다.

현재는 <콜라,사이다,환타> 3가지의 음료만 존재하지만

추후에는 <콜라,사이타,환타,포카리스웨트,핫식스> 5가지로 늘릴예정이다.


그렇다면 자판기클래스를 사용하는 모든 클래스에서는 수정이필요하며

이는 프로그램상 오류를 일으킬 확률이 높아짐 을 뜻한다.


객체지향이 나오면 항상 등장하는 말이있는데 이는 응집도는 강하게 , 결합도는 약하게 이다.

서로 다른 모듈이 2개가 존재한다고 하였을때 

이는 모듈 각각은 독립적으로 작용할수있도록 응집도가 강해야하고

다른 모듈을 참조하는 결합도는 낮아야한다.


이는 캡슐화와도 관계가있다.

위 예제에 클래스 두개는 독립적인 클래스이때문에 결합도가 낮아야하지만

위처럼 프로그래밍을 하였을때 결합도가 강해진다


즉 하나의 모듈이 변경되었을때 이를 사용한 다른 클래스에서도  수정이 필요하게되는것이다.

이는 유지보수에서 굉장히 치명적으로 작용한다.

따라서 위 프로그램을 수정할 필요성이 생긴다.


이번에는 위 클래스를 외부에서 필요한 기능만을 제외하고 은닉해보도록하겠다.



public class VendingMachine {
	
	private String drinks[] = {"콜라","사이다","환타"}; //음료수목록
	private String drink;
	private int price; //가격
	private int amt; //투입금액
	
	 
	VendingMachine(int amt){ 
		this.amt = amt; 
	}
	
	private boolean isEmpty(int num){ //해당음료수가 있는지 확인 
		return drinks.length < num;
	}
	
	public boolean checkingBlance(){
		return amt >= price;
	}
	
	public String getDrink(int num){ //음료수 가져오기 

		if( isEmpty(num) ){
			return "Drink get Fail";
		}
		
		drink = drinks[num];
		
		if( drink == "콜라" ){
			price = 1000;
		}else if( drink == "사이다" ){
			price = 900;
		}else if( drink == "환타" ){
			price = 800;
		} 
		
		if(!checkingBlance()){
			System.out.println("잔액부족");
			return "잔액: "+getBanlance();
		}
		amt = amt - price;
		return drink+"를 받는다.";
	}
	
	
	public int getBanlance(){//현재남아있는 잔액을 가져오고 금액 0원으로 초기화
		int temp = amt;
		amt = 0;
		return temp;
	} 
	
 }


변경된것은 현재 변수는 private 접근제어자로 현재 클래스에서만 호출할수있도록 하였으며

외부에 필요한 기능들만 public 접근제어자로 다른 모듈에서 접근할수 있도록 수정하였다.


이제 Client 클래스에서는 직접 변수의 값을 변경하지 않고 사용할수있으며

자판기의 속성과 행위가 변경되었을때는 자판기 클래스만 변경해주면 된다.


이와같이 객체지향 프로그램은 모듈화, 캡슐화 를 통해 적절하게 사용할경우

프로그램변경 요청시 적은 양의 코딩으로 프로그램 수정이 가능하다.


프로그래머로써 현업으로 일하다보면 버그 또는 요청사항 변경으로 수정이 빈번하게 알어나며

또는 수정이 또다른 버그를 만들어내는경우가 많이있다.

그러한 상황을 미리 예방하기 위해 클래스를 만들때는 신중하게 개발하는 버릇이 필요할것같다.


초보개발자의 블로그입니다.

잘못된 부분 알려주시면 고치도록 하겠습니다.