접근제어자와 캡슐화

2014. 11. 9. 17:19Basic/etc

반응형

1. 클래스 접근 제어자

생략(default) : 같은 패키지의 클래스에서만 객체(인스턴스)생성이 가능하다. 

public : 다른 패키지에서 객체(인스턴스)의 생성이 가능하다. 

2. 멤버에 접근 제어자

private : 같은 클래스 내에서만 접근이 가능, 외부객체 접근 불가(this키워드 사용하는 것들), 상속되지도 않는다.

생략(default) : 접근제어자가 없는 형태로 같은 패키지 내에서만 접근이 가능.

protected : 같은 패키지 내에서 사용가능하며, 다른 패키지라도 상속을 받은 클래스는 접근 가능.

public : 모든 객체에서 접근 가능.

※ 입문자의 경우 default 사용은 피하고 protected는 객체지향적 설계에서 사용이 많이 되니 입문자는 개념만 이해하고, 특별한 경우가 아니면 public과 private만 사용하자.

※ 오버라이딩시 접근제어자 : 부모 메서드보다 작은 범위의 접근 제어자를 사용할 수 없다. (외우지 말고 상식적으로 생각하자. 만약에 부모보다 작은 범위이 적용이 가능하다면 다형성 규칙에도 위배된다. 당연히 안되는 것이다)

ex) 부모 메서드가 protected 이면 오버라이딩시 protected or public, 부모 메서드가 public이면 오버라이딩시 public 이어야 한다.


  1. class A{
  2.     public void play(){}
  3. }
  4.  
  5. class B extends A{
  6.     @Override
  7.     public void play(){}
  8. }
  9.  
  10. class C extends A{
  11.     @Override
  12.     protected void play(){} // 컴파일 에러!
  13. }

3. 접근제어자를 이용한 캡슐화와 멤버변수(속성) 캡슐화

캡슐화란 간단히 말해 내부의 묘듈의 직접적인 접근을 막고 우회하는 접근방법을 제공함으로서 숨기고 싶거나 지켜야 될 규칙이 외부에서 알지 못하도록 하는 밥법이다.


  1. public class EncapsulationTest {
  2.     private void one() {
  3.         System.out.print("one -> ");
  4.     }
  5.     private void two() {
  6.         System.out.print("two -> ");
  7.     }
  8.     private void three() {
  9.         System.out.print("three -> ");
  10.     }
  11.    
  12.     public void play() {
  13.         this.one();
  14.         this.two();
  15.         this.three();
  16.     }
  17. }


클래스의 멤버변수(속성)를 외부에서 접근을 막고 public 메서드를 통해서 읽기와 쓰기가 가능하게 함으로서 잘못된 데이터 값이 들어오거나 악의적인 접근을 막을 수있다.

public class Member

{

private String id;

private int age;

 

public String getId()

{

return this.id;

}

public int getAge()

{

return this.age;

}

 

public void setId(String id)

{

this.id=id;

}

public void setPw(int age)

{

if(age<0) {

    return; //메서드 종료

}

this.age=age;

}

 

private void one() {

     System.out.println("one");

}

private void two() {

     System.out.println("two");

}

public void oneTwo() {

     one();

     two();

}

}

멤버변수나 메서드를 숨기기 위해서는 private이라는 접근 제어자를 사용했다. 예제에서 멤버변수들을 모두 private으로 선언하여 외부클래스에선 더 이상 그 변수들을 호출할 수 없게 된다. 변수(데이터)의 은폐화가 구현된 것이다.

하지만 이렇게 숨기기만 하면 또 다른 문제가 생긴다. 정작 숨긴 변수들에게 접근을 꼭 해야 할 상황에서조차 접근을 할수 없기 때문이다

변수들을 private선언 하더라도 접근할 수 있다면 public을 쓰는것과 같은것이지않느냐는 것이다. 물론 변수자체를 public을 사용하면 훨씬 편할 수 있다. 하지만 다른측면에서 생각해보자. 멤버변수중 외부에서 값은 열람은 하되 수정은 하지 못하게 하고 싶다면 어떻게 해야할까? 멤버변수를 public으로 그냥 노출시켜놓는다면 외부에서 수정하는 것을 원천적으로 막을 수 가 없다. 그렇기 때문에 get과 set 메서드를 선택적으로 두면 멤버변수는 읽기전용 혹은 쓰기 전용 식으로 데이터에 대한 접근 권한을 더 세분화 할 수 있다는 장점이 있고 또한 위의 코드를 보면 age같은 속성에는 음수값이 들어오면 안된다. 마이너스 나이라는것이 있을수가 없기 때문이다. 그렇기 때문에 set 메소드에 로직을 추가하여 음수값은 저장될 수 없게 원천적으로 막을 수가 있다.

onw(), two() 메서드 역시 private으로 외부호출을 막고 oneTwo() 메서드만을 public으로 외부호출이 되도록 하여 one(), two() 두 메서드가 연속적으로 같이 호출되도록만 하고 개별적 호출은 되지않도록 캡슐화 하였다.

캡슐화의 결정적인 이유는 데이터에 대한 읽기 쓰기 권한 구분과 입력된 데이터의 유효성을 검증할 수 있는 부분을 코드에 포함시킬 수 있다는 것 이다.

* 캡슐화(encapsulation) 또는 정보은닉(information hiding)으로 불리는 소프트웨어 설계 기본 원리중의 하나인 이 개념은 묘듈은 자신의 외부 API를 통해서만 다른 묘듈과 상호작용(통신, 메세지교환) 하며 자신의 내부 묘듈은 감추고, 다른 묘듈의 내부 작업에도 직접적으로 개입하지 않도록 설계하는 것이다.

* IDE툴로 이클립스를 사용한다면 간단히 setter와 gette를 만들수 있다.

이클립스에서 멤버변수(속성)의 setter와 getter만들기 - [에디터에서 마우스 우클릭] - [soruce]

 






4. 캡슐화 예제


시간은 0~23, 분은 0~59, 초는 0~59로 설정


  1. public class Time {
  2.     private int hour;
  3.     private int minute;
  4.     private int second;
  5.    
  6.     // getter
  7.     public int getHour() {
  8.         return hour;
  9.     }
  10.     public int getMinute() {
  11.         return minute;
  12.     }
  13.     public int getSecond() {
  14.         return second;
  15.     }
  16.    
  17.     // setter
  18.     public void setHour(int hour) {
  19.         if(hour>=0 && hour<=23){
  20.             this.hour = hour;
  21.         }else{
  22.             System.out.println("시간은 0~23을 입력");
  23.         }
  24.     }
  25.     public void setMinute(int minute) {
  26.         if(minute>=0 && minute<=59){
  27.             this.minute = minute;
  28.         }else{
  29.             System.out.println("분은 0~59을 입력");
  30.         }
  31.     }
  32.     public void setSecond(int second) {
  33.         if(second>=0 && second<=59){
  34.             this.second = second;
  35.         }else{
  36.             System.out.println("초는 0~59을 입력");
  37.         }
  38.     }
  39.    
  40. }



다음의 클래스는 아르바이트생에게 시간당 5000원씩 지급하는 시스템 클래스중 일부이다.


 

  1. class Pay
  2. {
  3.     public int rate; //시간당 단가
  4.     public Pay()
  5.     {
  6.         this.rate = 5000;
  7.     }
  8.    
  9.     // 시간당 급여를 지불하는 메서드
  10.     public int sendPay(int hour)
  11.     {
  12.          return hour*rate;
  13.     }
  14. }


ex1)무슨 문제가 발생할 수 있는가?

 

누군가 코딩중 실수로 rate값을 바꾼다면 어떻게 될까? 그래서.... 

 

  1. class Pay
  2. {
  3.   private int rate; //시간당 단가
  4.   public Pay()
  5.   {
  6.     this.rate = 5000;
  7.   }
  8.   // 시간당 급여를 지불하는 메서드
  9.   public int sendPay(int hour)
  10.   {
  11.     return hour*rate;
  12.   }
  13. }


ex2) 위와 같이 수정후에는 어떠한 문제가 발생할까?

 

rate값을 수정하지 못하지만 값을 읽어올수는 있어야 한다면...

프로그램 실행중에 rate값이 수시로 변해야 한다면...아무나 바꿀수 없게지만 권한있는 접근자에게는 허락하고 싶다면...

그래서...setter 와 getter를 이용한 캡슐화...

 

  1. class Pay
  2. {
  3.   private int rate; //시간당 단가
  4.   public Pay()
  5.   {
  6.     this.rate = 5000;
  7.   }
  8.   // 시간당 급여를 지불하는 메서드
  9.   public int sendPay(int hour)
  10.   {
  11.     return hour*rate;
  12.   }
  13.   //getter 추가
  14.   public int getRate()
  15.   {
  16.     return this.rate;
  17.   }
  18.   //setter 추가
  19.   public void setRate(String id, String pw, int rate)
  20.   {
  21.     if(id.equals("admin") && pw.equals("1234")
  22.     {
  23.       this.rate = rate;  
  24.     }
  25.     else
  26.     {
  27.       System.out.println("아무나 rate값을 변경할 수 없습니다.");
  28.     }
  29.   }
반응형

'Basic > etc' 카테고리의 다른 글

extends 와 implements의 차이?  (0) 2014.11.09
추상클래스와 인터페이스  (0) 2014.11.09
객체지향? 추상화?  (0) 2014.11.09
다형성  (0) 2014.11.09
포함? 상속?  (0) 2014.11.09