Programming/Java

[Java] 캡슐화와 은닉성에 대해 알아보자

cbw1030 2020. 10. 2. 19:56
반응형

안녕하세요. 즐거운 추석 연휴 기념으로 캡슐화와 은닉성에 대해 알아보는 시간을 갖도록 하겠습니다.

 

우선 캡슐화에 대해 설명을 하기에 앞서 자바에서 캡슐화를 하지 않았을 경우 생기는 문제점을 확인해보겠습니다.

다음과 같은 예제가 있습니다.

public class NumList {

    int size;
    int[] nums;
}

public class Program {

    public static void main(String[] args) throws IOException {
        NumList list = new NumList();
        list.size = 0;
        list.nums = null;
		
        load(list);
        int total = sum(list);
		
        System.out.println("합계: " + total);
    }
	
    static void load(NumList list) throws IOException {
        FileInputStream fis = new FileInputStream("res/data.txt");
        Scanner scan = new Scanner(fis);

        list.size = scan.nextInt();
        list.nums = new int[list.size];
		
        // 데이터 로드
        for (int i = 0; i < list.size; i++) {
            list.nums[i] = scan.nextInt();
        }

        fis.close();
    }
	
    static int sum(NumList list) {
        int sum = 0;
        for (int i = 0; i < list.size; i++)
            sum += list.nums[i];

        return sum;
    }

}
  • "res/data.txt"에는 '9 60 70 90 100 75 24 23 80 90'이 있다고 가정합니다.

위의 코드를 실행하면 콘솔에 다음과 같은 결과가 찍힙니다.

콘솔 출력 결과

 

자 그렇다면 NumList의 변수명 size가 마음에 들지 않아 변수명을 numSize로 바꾼다면 어떠한 일이 일어날까요?

public class NumList {

    int numSize;
    int[] nums;
}

size와 nums에 에러표시가 된 것이 보이나요? size 변수명만 바꿨음에도 불구하고 NumList의 객체를 사용한 모든 것들이 사용할 수 없도록 바뀌었습니다.

 

이유는 바로 Program 클래스에서 사용하고 있는 NumList 객체가 NumList에 종속되어 있기 때문입니다. 그렇기 때문에 NumList에서 어떤 것 하나를 수정하면 Program 클래스에서 동일하게 수정해주어야 정상 작동이 됩니다.

 

그렇다면 이렇게 하나하나 다 바꿔주어야 하는게 맞을까요?

 

아닙니다. 저희는 자바 언어를 사용하기 때문에 객체지향스럽게 소스코드를 짜야합니다. 그래서 여기서 사용되는 개념이 캡슐화입니다.

 

캡슐화(Encapsulation)는 객체지향 프로그래밍 5원칙 중 하나입니다.

캡슐화는 '데이터 구조와 기능을 묶는 것'을 의미합니다.

 

데이터 구조와 기능을 묶는다? 데이터는 변수를, 기능은 메서드를 의미합니다. 즉, 변수들과 그 데이터를 처리하는 코드들을 하나의 단위로 묶는 것입니다. 바로 아래와 같이 말이죠.

public class NumList {

    private int size;
    private int[] nums;
	
    public NumList() {
        size = 0;
        nums = null;
    }
	
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
    public int[] getNums() {
        return nums;
    }
    public void setNums(int[] nums) {
        this.nums = nums;
    }
	
    void load() throws IOException {
        FileInputStream fis = new FileInputStream("res/data.txt");
        Scanner scan = new Scanner(fis);

        size = scan.nextInt();
        nums = new int[size];
		
        // 데이터 로드
        for (int i = 0; i < size; i++) {
            nums[i] = scan.nextInt();
        }

        //scan.close();
        fis.close();
    }
	
    int sum() {
        int sum = 0;
        for (int i = 0; i < size; i++)
            sum += nums[i];

        return sum;
    }
	
}

음.. 그런데 처음보는 것이 있는데요. private 키워드와 get~, set~이 붙은 메서드입니다.

캡슐화된 클래스의 변수들은 클래스 외부에서는 절대 접근할 수 없습니다. 접근할 수 있도록 public 키워드를 붙인다면 캡슐화를 위배한 것입니다.

이를 방지하기 위해 private 키워드를 사용합니다. 그리고 클래스 외부에서 변수에 간접적으로 접근할 수 있도록 getters, setters 메서드를 사용합니다.  이러한 개념을 '정보 은닉'이라 합니다. 캡슐화와 정보 은닉은 뗄레야 뗄 수 없는 관계입니다.

 

자 NumList 클래스를 객체지향스럽게 바꿨으니 Program도 바꿔봐야겠죠?

Program.java

이렇게 간단하게 바꿀 수 있습니다.

NumList.java 파일에서 각 메서드의 static을 제거하여 list.load()처럼 접근이 가능하도록 하였습니다.

정상적으로 출력도 잘됩니다.

 

만약 NumList의 size를 numSize로 바꾼다면 NumList 클래스의 getters, setters만 변경해주면 에러없이 잘 돌아갑니다.

 

 

정리하자면 캡슐화의 장점은 다음과 같습니다.

1. 클래스 내부의 데이터 형태가 변경되어도 사용하는 코드를 변경할 필요가 없습니다.

2. 데이터가 변경되어도 다른 객체에 영향을 주지 않아 독립성이 유지됩니다. 즉, 유지보수가 좋습니다.

3. 클래스의 결합도가 낮아져 재사용이 용이합니다.

반응형