prgrms-web-devcourse / BE-Team-preArmand-Book-study

2 stars 2 forks source link

[아이템 50] 혹은 불변식이 깨지더라도 그 영향이 오직 호출한 클라이언트로 국한될 때로 한정해야 한다. #24

Closed epicblues closed 2 years ago

epicblues commented 2 years ago

page 306 마지막 문단 ~ 끝 ... 래퍼 클래스의 특성상 클라이언트는 래퍼에 넘긴 객체에 여전히 직접 접근할 수 있다. 따라서 래퍼의 불변식을 쉽게 파괴할 수 있지만 그 영향을 오직 클라이언트 자신만 받게 된다.

Leeyerimearth commented 2 years ago

민성님이 질문해주신걸 생각해보다가 추가로 궁금한 점이 생겼습니다.

따라서 래퍼의 불변식을 쉽게 파괴할 수 있지만 ..

래퍼클래스는 불변 클래스라고 알고있는데, 책에서 말하는 위 문장을 이해하지 못했습니다;;

kimziou77 commented 2 years ago

☠️ 제가 질문을 제대로 이해한지는 모르겠지만 제가 생각한것을 적어보겠슴니다


이부분에 대한 저의 해석은, 래퍼클래스로부터 값을 받아옴으로써 래퍼클래스 안에 있는 값들에 접근을 할 수 있겠지만,

래퍼클래스가 값을 전달해주는 방식은 새로 만들거나 값을 가져오는 것이다. (민환님이 소개해주신 일급컬렉션 소개 中)

이 글에서 래퍼클래스의 반환형은 방어적 복사본이라고 생각했고 이번장의 주제인 '방어적 복사본을 만들라' 와 일치해서 다음과 같은 문장이 작성되었다고 생각합니다!


// 1. B가 **가지고있는 A의 참조를 그대로** 클라이언트 에게 준다.
class B {
    A a;
    public A getA() {return a;}
}

//2. B가 **새로운 A인스턴스의 참조** 를 전달한다 (방어적복사)
class B {
    A a;
    public A getA() {return new A(a);}
}

이러한 상황에서 B가 싱글톤으로 관리되며, 이를 여러 클라이언트에서 공유하여 사용하는 상황이라고 가정해보면

  1. B가 가지고있는 A의 참조를 그대로 클라이언트 에게 준다.
    // 악의적인(혹은 미숙한) 클라이언트가 A클래스를 받아와서 의도하지 않은 행동을 수행하고 있다
    var a = b.getA(); // 원본 A를 받았다
    a.setIllegalValue(illegal); // 원본A값이 수정되었다
    // 다음번 사용자가 다시 A를 사용하려고 하고 있다.
    var a = b.getA(); // 원본 A를 받았다
    var value = a.getValue(); // 앞에서 수정된 이상한 A의 값을 받았다
    doSomething(value); // ⚠️오류!  

    이렇게 사용하는 쪽에서 이상한 짓을 해버리면 B에 있는 원본 A값 자체가 바뀐것이기 때문에 다음에 사용하는 클라이언트 2는 B에서 A와 연결된 모든 동작이 전체적으로 이상한 동작하게 될것입니다. 꼭 A클래스를 사용하지 않더라도요

그렇지만 이 상황에서 A를 2번 방법과 같이 방어적 복사를 해서 넘겨준다면 다른 클라이언트가 B클래스를 사용하더라도 A로 인한 사이드이펙트가 존재하지 않을겁니다!

  1. B가 새로운 A인스턴스의 참조 를 전달한다
    
    // 악의적인(혹은 미숙한) 클라이언트
    var a = b.getA(); // A의 복사본이 반환되었다.
    a.setIllegalValue(illegal); // 복사본에 이상한 값을 셋팅했다.
    var value = a.getValue(); // 본인이 셋팅한 이상한 값을 본인이 받았다.
    doSomething(value); // 본인이 피해를 입었다 쿨럭

// 다음번 사용자 var a = b.getA(); // A의 복사본이 반환되었다 var value = a.getValue(); // B에 있는 원본은 변화되지 않았으므로 정상적인 값을 받음 doSomething(value); // 정상수행



따라서 이런 참조를 가지고 있는 클래스를 만들때에는
이 참조를 클라이언트에게 넘겨줄때 (어떤 사이드 이펙트가 일어날지 모르니)
방어적으로 복사해서 넘겨주라는 이야기로 이해했습니다.