ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 접근제어자 / 캡슐화
    JAVA/개념 - 김영한 강의 2024. 8. 30. 15:51

     

    접근 제어자의 종류

    • private : 모든 외부 호출을 막는다(해당 클래스 내에서만 사용가능).
    • default (package-private): 같은 패키지안에서 호출은 허용한다.
    • protected : 같은 패키지안에서 호출을 허용하며, 패키지가 달라도 상속 관계의 호출 또 허용한다.
    • public : 모든 외부 호출을 허용한다.

     

    default(package-private)

    접근 제어자를 명시하지 않으면 같은 패키지 안에서 호출을 허용하는 default 접근 제어자가 적용된다.
    default 라는 용어는 해당 접근 제어자가 기본값으로 사용되기 때문에 붙여진 이름이지만, 실제로는 package private이 더 정확한 표현이다. 왜냐하면 해당 접근 제어자를 사용하는 멤버는 동일한 패키지 내의 다른 클래스에서
    만 접근이 가능하기 때문이다. 참고로 두 용어를 함께 사용한다.

     

    ex) 아래와 같이 접근제어자가 아무것도 붙여지지 않은게 default다.

    int volume;

     

     

     

     

    캡슐화(Encapsulation)

    캡슐화는 데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근을 제한하는 것을 말한다. 캡슐화를 통해 데이터의 직접적인 변경을 방지하거나 제한할 수 있다. 캡슐화는 쉽게 이야기해서 속성과 기능을 하나로 묶고, 외부에 꼭 필요한 기능만 노출하고 나머지는 모두 내부로 숨기는 것이다. 그리고 캡슐화를 안전하게 완성시킬 수 있는 장치가 바로 접근 제어자다. 

     

     

    객체에는 속성(데이터)과 기능(메서드)이 있다.

     

    1. 캡슐화에서 가장 필수로 숨겨야 하는 것은 속성(데이터)이다. 객체 내부의 데이터를 외부에서 함부로 접근하게 두면, 클래스 안에서 데이터를 다루는 모든 로직을 무시하고 데이터를 변경할 수 있다. 결국 모든 안전망을 다 빠져나가게 된다. 

     

    우리가 일상에서 생각할 수 있는 음악 플레이어를 떠올려보자. 음악 플레이어를 사용할 때 그 내부에 들어있는 전원이나, 볼륨 상태의 데이터를 직접 수정할 일이 있을까? 우리는 그냥 음악 플레이어의 켜고, 끄고, 볼륨을 조절하는 버튼을 누를 뿐이다. 복잡하게 음악 플레이어의 내부를 까서 그 내부 데이터까지 우리가 직접 사용하는 것은 아니다. 객체의 데이터는 객체가 제공하는 기능인 메서드를 통해서 접근해야 한다.

     

    2. 기능을 숨겨라
    객체의 기능 중에서 외부에서 사용하지 않고 내부에서만 사용하는 기능들이 있다. 이런 기능도 모두 감추는 것이 좋다. 우리가 자동차를 운전하기 위해 자동차가 제공하는 복잡한 엔진 조절 기능, 배기 기능까지 우리가 알 필요는 없다. 우리는 단지 엑셀과 핸들 정도의 기능만 알면 된다.

     

    만약 사용자에게 이런 기능까지 모두 알려준다면, 사용자가 자동차에 대해 너무 많은 것을 알아야 한다. 사용자 입장에서 꼭 필요한 기능만 외부에 노출하자. 나머지 기능은 모두 내부로 숨기자 정리하면 데이터는 모두 숨기고, 기능은 꼭 필요한 기능만 노출하는 것이 좋은 캡슐화이다

     

     

    public class BankAccount {
    	 private int balance; // 잔액 기본으로 설정돼서 0원이다
     
     
     // 입금 메서드
     	public void deposit(int amount) {  // amount=입금금액
     		if (isAmountValid(amount)) {
     			balance += amount;
     		} else {
            System.out.println("유효하지 않은 금액입니다.");
     		}
     }
     
     // 출금 메서드
     	public void withdraw(int amount) {  // 여기선 amount=출금액
     		if (isAmountValid(amount) && balance - amount >= 0) {  // 출금액이 0보다 크고, 잔액-출금액>0이어야 
    			 balance -= amount;  // 출금할 수 있다
     			} else {
     			System.out.println("유효하지 않은 금액이거나 잔액이 부족합니다.");
    			}
     	}
     
     // 잔액 조회 메서드 : 외부에서 할 수 있게
     	public int getBalance() {
     		return balance;
    	 }
     
     // 입출금액은 반드시 0보다 커야함 : 이걸 외부에서 알 필요는 없음 당연한 것!
     	private boolean isAmountValid(int amount) { 
     		return amount > 0;
    		 }
    }

     

     

    • amount는 메서드 내부에서만 사용되는 지역 변수이기 때문에 메서드가 호출될 때마다 각기 다른 값으로 설정된다. amount는 메서드 호출 시마다 외부에서 전달되는 값이고 메서드 안에서만 유효하기에 클래스 멤버 변수로 선언할 필요가 없다.
    • 메서드 만들 때 void로 할 건지 int boolean으로 할 건지 생각하고 만들기 좀
    • 만약 isAmountValid() 를 외부에 노출하면 어떻게 될까? BankAccount 를 사용하는 개발자 입장에서는 사용할 수 있는 메서드가 하나 더 늘었다. 아마도 입금과 출금 전에 본인이 먼저 isAmountValid() 를 사용해서 검증을 해야 하나? 라고 의문을 가질 것이다.
    • 만약 balance 필드를 외부에 노출하면 어떻게 될까? BankAccount 를 사용하는 개발자 입장에서는 이 필드를 직접 사용해도 된다고 생각할 수 있다. 왜냐하면 외부에 공개하는 것은 그것을 외부에서 사용해도 된다는 뜻이기 때문이다.  그러면 잔고가 변경되는 문제가 발생하기 때문에 위험해진다. 

    댓글

Designed by Tistory.