JAVA의 가장 기본이 되는 내용

캡슐화

cwchoiit 2024. 3. 26. 20:11
728x90
반응형
SMALL

참고 자료:

 

김영한의 실전 자바 - 중급 1편 | 김영한 - 인프런

김영한 | 실무에 필요한 자바의 다양한 중급 기능을 예제 코드로 깊이있게 학습합니다., [사진]국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바

www.inflearn.com

캡슐화는 객체 지향 프로그래밍의 중요한 개념 중 하나다. 캡슐화는 데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근을 제한하는 것을 말한다. 캡슐화를 통해 데이터의 직접적인 변경을 방지하거나 제한할 수 있다.

 

캡슐화는 쉽게 이야기해서 속성과 기능을 하나로 묶고, 외부에 꼭 필요한 기능만 노출하고 나머지는 모두 내부로 숨기는 것이다.

캡슐화는 그러니까 두가지 파트로 나뉘어지는데, 1. 속성과 기능을 하나로 묶는다. 2. 외부에 꼭 필요한 기능만을 노출시키고 나머지는 숨긴다. 그럼 여기서 1번은 클래스 내 필드를 만들고 그 필드를 가지고 어떤 행위를 할 것인가에 대한 메서드를 정의하는 것으로 생각할 수 있다. 2번은 그 필드와 메서드를 접근 제어자를 통해 제한하는 것이다.

 

그럼 어떤것을 숨길까?

 

데이터를 숨겨라

객체에는 속성(데이터)과 기능(메서드)이 있다. 캡슐화에서 가장 필수로 숨겨야하는 것은 속성(데이터)이다. 예를 들어, Account라는 클래스가 있을 때 해당 클래스의 속성으로 'balance'라는 필드가 있으면 외부에서 이 필드에 직접적으로 접근이 가능하면 어디서나 잔고에 돈을 더하거나 뺄 수 있을것이다. 최악으로 가는 길이다. 자동차를 예시로 생각해보면 우리가 자동차를 운전할 때 자동차 부품을 다 열어서 그 안에 있는 속도계를 직접 조절하지 않는다. 단지 자동차가 제공해주는 엑셀이라는 기능을 사용해서 엑셀을 밟으면 자동차가 나머지는 다 알아서 하는 것이다.

 

객체의 데이터는 객체가 제공하는 기능인 메서드를 통해서 접근해야 한다.

 

기능을 숨겨라

객체의 기능 중 외부에서 사용하지 않고 내부에서만 사용하는 기능들이 있다. 이런 기능도 모두 감추는 것이 좋다. 예를 들어 자동차 엑셀을 밟는것만 알면 되는데 엑셀을 밟을 때 자동차가 하는 내부적으로 하는 행위를 우리가 안다고 자동차가 앞으로 가는것에 어떤 도움을 줄 수 있는가? 오히려 알면 독이 될 수도 있다. 

 

정리하면 데이터는 모두 숨기고, 기능은 꼭 필요한 기능만 노출하는 것이 좋은 캡슐화이다.

 

아래 캡슐화가 잘 된 코드로써 예를 들어보자.

Account

public class Account {
    private int balance;

    public Account(int balance) {
        this.balance = balance;
    }

    public int deposit(int amount) {
        balance += amount;
        return balance;
    }

    public int withdraw(int amount) {
        balance -= amount;
        return balance;
    }

    public void status() {
        System.out.println("현재 잔고: " + balance + "원");
    }
}

 

위 코드를 보면 은행 계좌 클래스임을 알 수 있고 필드로 'balance'라는 속성을 가진다. 그 필드는 외부에서 접근하지 못하는 'private'이다. 그리고 이 계좌라는 클래스에서 할 수 있는 행위는 입금, 출금, 잔고 상태 확인이 있을 수 있는데 각각의 기능은 외부에서도 사용가능 하도록 'public'으로 만들었다. 

 

그럼 이 Account 클래스를 가져다가 사용하는 코드를 보자.

AccountMain

public class AccountMain {
    public static void main(String[] args) {
        Account account = new Account(10000);

        account.deposit(5000);
        account.status();
        account.withdraw(1500);
        account.status();
    }
}

외부에서는 이 클래스의 객체를 만들어서 입금, 상태 확인, 출금, 상태 확인 기능을 차례대로 사용했다. 아무런 문제가 없다. 

이제 여기서 Account 클래스에 새로운 메서드를 만들것이다. 그 메서드는 외부에서 접근하지 못하는 기능이다. 

바로 입금이나 출금할 때 금액에 대한 유효성 검사를 하는 메서드이다.

private boolean isAmountValid(int amount) {
    return amount > 0;
}

 

그리고 그 메서드를 deposit(), withdraw()에 추가했다. 이렇게 내부에서만 사용하고 외부에서는 사용할 필요가 없는 기능은 숨기는 것이다. 

public int deposit(int amount) {
    if (isAmountValid(amount)) {
        balance += amount;
    } else {
        System.out.println("입금할 금액에 문제가 있습니다.");
    }
    return balance;
}

public int withdraw(int amount) {
    if (isAmountValid(amount) && balance > amount) {
        balance -= amount;
    } else {
        System.out.println("출금할 금액에 문제가 있습니다.");
    }
    return balance;
}

 

그럼 만약 이 메서드가 외부에서 접근이 가능하게 만들었다면 어떤 문제가 발생할까? 만약 Account를 만드는 개발자와 Account를 가져다 사용하는 개발자가 나뉘어져 있다면 사용하는 개발자는 다음과 같은 화면을 볼 것이다.

Account 객체를 만들었고 그 객체에 .을 찍어보니 다음과 같이 isAmountValid()라는 메서드가 있다. 그럼 가져다 사용하는 개발자는 생각할 것이다.

"음.. 내가 유효성검사를 한 후 입금이나 출금을 해야하나?"

너무나 합리적인 생각이다. 왜냐하면 public으로 접근 제어자를 설정했다는 의미는 외부에서 가져다가 사용하라는 뜻이다. 그래서 사용하는 개발자는 다음과 같은 끔찍한 코드를 짠다. 이미 내부에서 검사를 하는데 검사를 또 하고 있는것이다. 

 

또는 balance라는 필드를 public으로 변경해보자. 다음과 같이 사용하는 개발자는 balance라는 필드가 public으로 되어 있는것을 보고 생각한다. 

"아 내가 직접 잔고에 접근해서 잔고를 수정할 수 있겠구나?"

이것 또한 합리적이다. 마찬가지로 public으로 선언한 의미는 곧 외부에서 사용하란 소리이기 때문이다. 그럼 다음과 같이 끔찍한 코드가 작성이 가능해진다. 갑자기 사용자의 통장이 마이너스 통장이 되버린다.

 

이런것을 보고 캡슐화가 깨졌다고 표현한다. 그래서 접근 제어자와 캡슐화를 통해 데이터를 안전하게 보호하는 것은 물론이고, 사용하는 개발자 입장에서도 해당 기능을 사용하는 복잡도도 낮출 수 있다.

728x90
반응형
LIST

'JAVA의 가장 기본이 되는 내용' 카테고리의 다른 글

final  (0) 2024.03.27
자바 메모리 구조 ✨  (0) 2024.03.27
Class 레벨의 접근제어자  (0) 2024.03.26
Package에서 딱 하나 헷갈리는 한가지  (0) 2024.03.26
생성자 - this()와 오버로딩  (0) 2024.03.26