2011년 1월 4일 화요일

접근제한자가 객체지향의 중요한 특징이라고?

흔히들 객체지향 언어의 특징중에 하나로 '정보 은닉'이라는 것을 든다.

접근제한이라는 설명을 하면서 이런 특징을 설명하는데..
사실 이것은 객체지향 패러다임과 관련이 있다고 할 수 있는지에 대해서는 아직도 의문이 든다.

왜 내가 이런 생각을 하는지 한번 얘기를 풀어보도록 하자.

우선 객체지향 패러다임에서 객체(object)라는 것은 언어로 말하자면 변수를 별도의 공간에 각 각 저장하는 방식을 의미한다. 즉 Java의 경우라면 클래스의 복사본의 구조를 그대로를 메모리 상에 별도의 영역에 할당하는 방식이다.

이렇게 되면 각 메모리의 공간을 접근하기 위해서 포인터(pointer)를 활용하게 될 것이고,
그것을 Java에서는 레퍼런스라는 이름으로 부르고 있다.

접근제한이라는 것은 간단히 말하자면 이 공간에 접근하는 것을 특정한 키워드를 이용해서 제어하는 것을 의미한다.

즉 접근 제한이라는 것은 메모리 공간을 마음대로 접근하지 못하게 하는 행위를 의미하는 것이지, 객체지향에서만 사용되는 특별한 개념은 아니라는 것이다.


접근 제한이라는 말 보다는 오히려 데이터나 로직에 접근할 수 있는 하나의 울타리나 상황(Context)라는 개념이 더욱 적합한 개념이 아닐까?

-----------------------------------------------------------------
사실 접근 제한을 보면 상당히 말도 안되는 구성을 가지고 있다.

우선 가장 접근제한 레벨이 높은 private을 한번보자.

private은 외부 클래스에서는 접근이 불가능하다는 판단이다. 재밌는 것은 이 범위라는 것이 단순히 클래스의 '{ }'에 대해서만 한정적이라는 사실이다.


public class Save {

private int total;
public void addMoney(int amount){
total = total + amount;
}
public void withdraw(int amount){
total = total - amount;
}
public void displaySave(){
System.out.println("CURRENT :" + total);
}
}

위의 코드를 보자. 
total이라는 데이터가 private으로 정의되어 있다. 따라서 외부의 클래스에서는 이 데이터에 access를 할 수 없게 되어 있다. 

하지만 이 접근 제한은 만일 객체를 사용하는 main 메소드를 안쪽에 만들어 버리면 참으로 무용지물이 된다. 


public class Save {

private int total;

---- 중략
public void displaySave(){
System.out.println("CURRENT :" + total);
}

public static void main(String[] args) {
Save s1 = new Save();
s1.total = 1000;
s1.displaySave();
}
}


위의 코드는 실제로 에러가 발생하지도 않고, 실행되 제대로 된다.
이 코드를 보면 객체지향에서의 '정보의 은닉'이라는 것은 절대 환상이다.
만일 정말로 객체의 정보가 은닉되어서 감추어 진다면 main메소드가 실행되는 환경에서조차도 s1이 가진 정보는 보호되어야 하지 않을까?

-----------------------------------------------------------------------
그렇다면 우리는 도대체 private을 뭐라고 이해해야만 하는 것일까?

일단은 우리가 쉽게 Java책들에서 찾아볼 수 있는 개념을 한번 정리해 보자.

* 접근제한을 하면 외부 클래스에서 접근할 수 없다(private)

* 하지만 private이라고 해도 동일한 클래스 내에서는 접근이 가능하다. static이건 아니건 상관은 없다.

이 두가지 사실만으로 판단해 보면 결국 접근제한을 한다는 것은 마치 코드의 영역을 표시해 주는 '{ }'와 유사하지 않을까?

예를 들어 조금은 과장된 방식의 코드를 작성해 보자.


public class ForEx {

{
int j = 10; 
for(int i = 0; i < 10; i++){
System.out.println(i + j);
}
}
}



이 코드는 전혀 문제가 없는 코드이다. '{ }'를 이용해서 변수의 범위에 대한 제한을 걸어 둔 것 뿐이다.


public class ForEx {

{
int j = 10; 
for(int i = 0; i < 10; i++){
System.out.println(i + j);
}
}
//이러면 에러 
j++;
}
재밌는 것은 접근제한 보다도 오히려 위와 같은 '{ }'가 변수나 로직에 대한 접근을 더욱 엄격하게 할 수 있다는 것이다. 


이제 슬슬 결말로 가보자. 

우리가 배우는 접근제한자 라는 것은 우리가 생각했던 것만큼 객체지향적이지도 않을 뿐더러 프로그래밍에서 영역을 구분하는 '{ }'보다도 못하다는 것이다. 

그럼 접근제한자를 왜 생각해 냈을까?  
클래스의 내부에서만 사용되는 변수? 

동일한 정보(클래스는 일종의 메타데이터이므로)를 가지는 것들만의 일종의 필터(filter)가 아닐까? 

필터(filter)라는 가정을 해 보자. 

모든 객체는 자신이 속한 클래스의 정보를 알아 낼 수가 있다. 흔히 reflection기술을 이용하면 이 사실을 좀 더 알수 있을 것이다. 

만일 A라는 객체와 B라는 객체가 동일한 클래스에서 나온 객체라면 이 두 객체는 서로가 동족(? 동일한 클래스에서 생성되었음)이라는 것을 알수 있을 것이다. 

그렇다면 이 동족들 사이에서만 사용될 수 있는 일종의 변수의 이름을 생각해 보면 어떨까? 
private이 붙은 변수는 즉 이런 동일한 족속들이 사용하는 일종의 정해진 변수의 이름이라고만 생각해 보면 어떨까? 

default 접근제한자의 경우라면 동일한 패키지의 이름으로  정보를 가진 객체만 사용하는 '은어'와 같은 존재라고 보면 어떨까? 


내가 생각하는 접근제한자라는 것은 이런 개념이다. 
 
 


댓글 없음:

댓글 쓰기