Whiteship's Note

Reference의 위험성

Java : 2006.10.27 12:40


어떤 객체가 있습니다. 그리고 그 객체를 참조하고 있는 어떤 변수가 있습니다. 그 변수를 레퍼런스 변수라고 말합니다.

예를 들어 Data 객체가 있고 그 객체를 참조하는 endDate라는 레퍼런스 변수가 있습니다.


그리고 endDate라는 레퍼런스 변수를 누군가 가져다 씁니다.

pubic class User(){
   SchoolSession session = new SchoolSession();
   public void showEndDate(){
        Date viewDate = session.getEndDate(); //여기서 endDate의 레퍼런스 값을 가져옵니다.
        System.out.println(endDate);
   }
}

이 경우에 아무런 문제가 없이 그냥 endDate를 가져와서 화면에 뿌려 줍니다. 그런데.. 만약에
뿌리기 전에.. endDate.set( ~~~ ) 이런 식으로 값을 바꿔버리면 endDate가 참조 하고 있는 객체의 정보가 바뀌게 됩니다.
(물론 여기서는 Date type으로 얘기를 하고 있어서 메소드 이름이 안맞을 수 있습니다. GregorianCalendar type의 경우 set( int yyyy, int mm, int dd) 와 같은 메소드가 있고 그것도 지금 이 경우에 해당하는 상황이 발생할 수 있습니다.)


어떤 객체의 레퍼런스를 넘겨 주면 그 객체에 이러한 영향을 끼칠 수가 있습니다. 다음 번에 이 객체에 접근 하는 client는 가짜 정보, 잘못된 정보를 가지고 있는 객체에 대한 레퍼런스를 가져가게 되겠죠.

멤버 변수들을 private으로 설정해 두어도 public 접근 지시자인 setter를 가지고 있는 객체들이라면 모두 이러한 일이 발생할 여지가 있는 것입니다.

그럼 어찌해야 할까요?
1. 외부에 어떤 객체에 대한 레퍼런스를 주어도 원래 객체가 가지고 있던 정보를 유지하고 싶을 때가 있고
2. 어떤 객체의 정보를 변경할 수 있는 권한을 가진 Client만 객체의 setter나 멤버변수에 직접 접근 하게 하고 싶을 때가 있을 수 있겠네요.

이미 존재하는 API들의 대다수 클래스들이 위와 같은 방식으로 접근이 가능하다는 것은 클래스를 잘 구현하는데서 해결책을 찾아야 하는 것이 아니라 클래스를 어떻게 사용해야 객체와 레퍼런스를 어떻게 사용해야 이러한 위험을 없앨 수 있는지에 생각해 봐야겠습니다.

한가지 어제 학교에서 스터디 도중 논의된 이야기로..

원래 있던 객체의 레퍼런스를 통해서 전달할 레퍼런스가 참조하고 있는 객체의 Clone을 만드는 것입니다. 그리고 그 Clone에 대한 레퍼런스를 넘겨 주는 것이죠. 그렇게 하면 Client에서 극 Clone의 정보를 가져가 쓰고 그 Clone의 정보를 마음대로 수정해도.. 원본 객체의 정보에는 전혀 영향을 주지 않게 됩니다.


이 경우에는 오직 endDate 라는 레퍼런스 변수만 원래 객체에 접근할 수 있는 권한을 가지고 있습니다. 그리고 다른 Client들은 원래 객체의 Clone을 레퍼런스 하는 변수만을 가지게 되는 것이죠. 즉 위에서 생각해본 2번의 경우에 해당합니다.

어떤상황에서도 즉 endDate 레퍼런스 변수 까지도 자신이 참조하고 있는 객체의 정보를 변환하지 않게 하려면.. 그건 방법이 없어보입니다. 적어도 그 클래스에 setter가 없다면 모를까 마땅한 방법이 떠오르지 않습니다.

소스 코드로 확인해 보겠습니다.

먼저 endDate를 가지고 있는 Session class를 보겠습니다.

이제 여기 있는 endDate를 가져다 사용하는 Clinet 소스 코드입니다.

실행 결과 입니다.

실행 결과 역시 endDate가 참조하는 원래 객체의 정보가 바뀐 것을 확인 할 수 있었습니다.

'Java' 카테고리의 다른 글

What is Object?  (12) 2006.11.01
Agile Java 2장 연습문제 풀기  (2) 2006.10.29
Lazy Initialization 언제 사용 해야 될까요?  (9) 2006.10.28
Agile Java 1장 연습문제 풀기  (2) 2006.10.27
JUnit 3.8 과 JUnit 4의 차이  (0) 2006.10.27
Reference의 위험성  (10) 2006.10.27
다중 구현(?)  (2) 2006.10.23
Interface  (2) 2006.10.16
Lesson 3. Strings and Packages  (0) 2006.10.06
Lesson 2. Java Basics  (0) 2006.10.03
Lesson 1. Getting Started  (0) 2006.09.25
top

  1. Favicon of https://springframework.tistory.com BlogIcon 영회 2006.10.27 14:45 신고 PERM. MOD/DEL REPLY

    재미있는 이슈로군.

    '클래스를 잘 구현하는데서 해결책을 찾아야 하는 것이 아니라 클래스를 어떻게 사용해야 객체와 레퍼런스를 어떻게 사용해야 이러한 위험을 없앨 수 있는지'

    대개 이런 식으로 해결을 하지.

    Why getter and setter methods are evil 이라는 글이 있는데
    http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html

    Encapsulation에 초점을 둔 재밌는 글인데
    session.setEndDate라는 것은 대부분의 개발자의 편의를 위한 것이지만 그리 적절한 것은 아닐 수 있지.
    대개 학기의 시작과 종료일자는 명시적으로 결정해주는 경우는 없지.
    뒤틀어진(?) 설계지... ^^

    대개는 한 주에 몇번 그리고 총 몇 번의 수업을 하느냐
    그리고, 그 해의 달력에 의해 산정되니까.

    이것이 진정한 Encapsulation이고..
    private 이나 public 이니 하는 것은 encapsulation을 위한 부가적인 장치에 지나지 않지.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.10.27 16:28 신고 PERM MOD/DEL

    예 ㅋ 안그래도 이 글을 쓰면서 저 링크가 생각났었는데 그 때 자세히 보진 않고 첫 단락만 봤었거든요.

    자바에서 게터 세터는 흔하지만 그렇다고 OO(객체 지향)에서도 흔한 것은 아니다.. 였나..

    일단 읽어봐야겠어요. :)

  2. 현동규 2006.10.30 13:55 PERM. MOD/DEL REPLY

    으으.. 도저히 방법이 안떠오르네요.

    항상 프리미티브로 내줄것도 아니공 -0- ..

    위에 Date 같은경우에는 Calender 클래스를 이용해서 Long으로 반환이 가능하더군요.

    그렇게 우회적으로 바꿔주면 될것 같습니다.

    그리고 클라이언트에서 필요할때 Date객체로 바꿔주면 되겠죠 Date(Long ) 생성자를 이용해서요.

    이것도 게으른 처리의 한 예가 될수도 있겠네요 ^^



    자바가 GC를 해주지만

    그래도 쓰레기 객체를 클라이언트 몰래 만들어주는것은 별로 좋지 않은 방법같습니다.

    예상못한 out of memory 라든지, 실행 속도면에서도 그렇구요!!


    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.10.30 20:47 신고 PERM MOD/DEL

    그러니까 무턱대고 getter, setter를 만들어 두면 안되는거지..

    정말 필요한 getter, setter만 만들어야 되는데 이미 습관화 되어있는 사람들은 무조건 필드들 선언 한 다음에 Alt+Shift+S 눌러서 Generate Getter/Setter 해버리기 쉽거든...(사실 나도 여태 그래왔지..ㅋㅋ 그렇기 때문에 이클립스 단축키까지 외우고 있자나?)

    간편하니깐..

    그런데 우리가 공부하고 있는 Agile Java는 그런 모습을 전혀 한번도 찾아 볼 수가 없지 왜?

    테스트 코드 부터 만들기 때문에.. 필드의 값을 가져오거나 변경시켜야 할 필요가 있을 때만 그런 메소드를 만들게 되는거지..

    그리고 그 메소드를 만들때 접근 지시자까지고 꼼꼼히 신경을 써주고 있지.. 처음에는 default로.. 그다음에 protected 그래도 안되면 public..이런식인거지.

    그래서 설계가 일단 굉장히 중요하다는 것이고..

    그다음 구현할 때도 주의가 필요한거고..

    이런 사항들을 신경쓰지 않고 만들어 둔 class를 사용해야만 한다.. 그럴 땐 초난감? ㅋㅋ

    모르겠다 나도

  3. 찬욱 2006.11.02 10:18 PERM. MOD/DEL REPLY

    제가 학교 갔을 때 했던 얘기군요...

    생각해보니까 제가 주제랑 조금 엉뚱한 풀 얘기를 했더군요..--''

    하지만 조금 달리 생각해보면.. 동규가 말한 out of memory나 실행 속도 면에서는 pool을 제공해서 사용하면 더 좋은 해결책을 찾을 수 있지 않을까요..

    머, 그런 생각을 해봅니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.11.02 11:02 신고 PERM MOD/DEL

    내가 pool을 어떻게 왜 쓰는지를 잘 몰라서.. DB connectino pool 같은 경우는 매번 커넥션 객체 생성하는데 드는 시간을 줄이려고 미리 메모리에 여러개 만들어 두고 그중에서 가져다 쓰고 나중에 pool장에 튜브처럼 반환하는 거로 쓰는 경우밖에 모르거든..

    그런데 여기서 얘기하는 객체의 상태를 변화 시킬 수 있는 레퍼런스의 위험성을 풀장에 cron 객체 여러개를 튜브처럼 띄워 두고 사용하는 방식을 사용하면.. 그것도 하나의 방법이라고 볼 수 있을 것 같네.. :)

    하지만 역시 근본적인 해결을 하려면 설계가 잘 되있어야겠다는 생각이 드는군..

  4. Favicon of http://decoder.egloos.com BlogIcon decoder 2006.11.09 11:39 PERM. MOD/DEL REPLY

    안녕하세요? 엔터프라이즈 컴퓨팅 같이 듣고 있는 이대엽입니다.
    블로깅도 프로그래밍만큼이나 열심히 하시는군요! . :)

    이 이슈는 작년에 들었던 프로그래밍 입문 시간에 다룬 내용으로
    Privacy Leak에 관한 내용과 다소 일치하는 내용인것 같군요.
    Absolute Java(by Walter Savitch)라는 책에 이 내용이 나오는데,
    거기에선 세터와 게터 메소드의 내용을 바꾸는 식으로 문제를 해결하고 있습니다.
    즉, 세터 메소드의 경우
    public void setEndDate(Date newDate) {
    // consistent() 메소드는 현 객체의 날짜와 새로 받는 날짜의 유효성을 검사하는 메소드가 되겠죠?
    if (consistent(this.endDate, newDate) {
    endDate = new Date(newDate);
    } else {
    System.out.println("Inconsistent dates. Aborting...";);
    System.exit(0);
    }
    }

    그리고 게터 메소드의 경우
    public Date getEndDate() {
    return new Date(endDate);
    }
    이렇게 구현할 경우 게터를 호출하는 입장에선 새로운 Date 객체를 받으니 수정하든 말든 원본의 내용은 변경이 불가능하죠.

    도움이 되셨으면 하네요. 그럼 수업시간에 뵙죠.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.11.09 11:53 신고 PERM MOD/DEL

    반갑습니다. 헤헷 저보다 대엽씨가 훨씬 열심히 하시는 것 같은데요? :)

    리플로 달아 주신 내용도 일종의 Clone을 만들어서 주는 방식이군요.

    객체 내부의 data가 절대로 변하지 말아야 할 중요한 것이라면 이런 방식으로 하는 것이 좋겠네요.

    역시 때에 따라 해결책은 그 때 그 때 다를 것 같습니다.

  5. Favicon of https://zerry82.tistory.com BlogIcon 동자~ 2006.11.09 16:53 신고 PERM. MOD/DEL REPLY

    답변이 조금 늦었네요

    제가 설명이 부족했어요!

    게으른 처리와 비슷한 이유는

    Long을 반환하지만 이걸 바로 Date형식으로는 쓸수 없거든요

    사용자가 Long받았지만 Date로 쓸려면

    Date(Long 어쩌구)로 다시 객체를 생성해야만 쓸수 있습니다.

    그..이야기 였습니다.

    저의 이야기의 요점은.

    사용자 몰래 객체 생성은 별로 좋지 않은것 같고,

    객체생성을 피할수 없다면 사용자의 선택에 의해 만들어야 한다.

    입니다만..

    형이 말하신대로 설계시 상황상황 다를것 같네요~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.11.09 17:08 신고 PERM MOD/DEL

    ㅇㅇ 무슨 얘긴지 알겠는데.. 너의 댓 글 중에 사용자는 Date 객체를 사용하는 클래스를 말하는 거지?

    내부 구현이야 어떻든 사용자가 알 필요는 없지 그냥 어떤 메소드를 사용해서 객체를 받아서 사용할 수가 있는지만 알면 되지 않을까?

    구현을 어떻게 해야 할지는 설계자와 개발자의 몫일것 같에...

Write a comment.




: 1 : ··· : 131 : 132 : 133 : 134 : 135 : 136 : 137 : 138 : 139 : 140 :