Today
-
Yesterday
-
Total
-
  • 엑세스 함수(getter/setter)를 올바로 사용하기
    Practice/C++, Java 2017.02.13 13:05

    두 줄 요약:
    객체의 속성을 읽고 쓰는 일관된 표현 방식을 제공하라. 엑세스 함수를 추천한다.[각주:1]
    시그니처의 변경 가능성이 없는 것만 공개하라.


    엑세스 함수를 사용하면 규칙이나 기능을 추가하기 쉽다.

    Null을 할당하는 것을 허용하지 않거나 객체의 속성을 외부에서 바뀔 수 없는[각주:2] 규칙이 더해질 수 있다.
    메모이제이션(memoization)[각주:3]과 같은 기능이 나중에 추가될 수도 있다.
    엑세스 함수를 사용했으면, 의존하고 있는 외부 객체의 수정 없이 규칙과 기능을 추가할 수 있다.
    변경 가능성이 없는 속성이라면 공개해도 괜찮을까?
    아래 섞어쓰기 문제 때문에 피하는 것이 좋다.


    일관된 방법을 제공하라.

    엑세스 함수와 공개 변수를 같이 쓰면 일관성이 깨진다.[각주:4]
    일관성이 없으면 매번 어떤 방식으로 접근해야 하는지 알아내야 해서 불편하다.
    더불어, 여러가지 방식을 섞어서 쓰면 코드가 더러워진다.

    h = t.getHours();   // getter
    m = t.minutes;      // get a public field
    t.setSeconds(sec);  // setter
    t.minutes = min;    // set a public field


    결론적으로 객체의 속성을 읽고 쓸 때는 언제나 엑세스 함수를 사용하라.


    getter/setter에 대한 오해

    setter/getter 쓴다고 정보은닉이 되는 게 아니고 사실은 정보은닉을 망치게 됩니다.
    저는 getter/setter 많이 쓴 것은 나쁜 냄새(bad smell)로 봅니다.
    getter setter는 객체지향과 거리가 멀며 써야 할 곳은 한정되어 있다


    문맥과 떨어져서 해석하면,
    "엑세스 함수보다는 공개 변수를 사용하는 것이 좋다"
    라고 오해할 수 있다.
    이는 잘못된 해석이다.


    정확한 의미는 외부에서 내부의 상태를 직접 변경하는 설계가 나쁘다는 것이다.
    이런 나쁜 설계에서는 어떤 방식이든지 변수를 직접 건드릴 수 밖에 없다.
    공개 변수 사용은 당연히 좋지 않고, getter/setter도 가능하면 적게 공개하도록 설계해야 한다.


    예를 들면, 밥을 먹으면 배부른 상태가 되어야 한다.

    foo.eat();
    assert(foo.isFull() == true);

    반면, 객체 밖에서 배부른 상태를 직접 변경하는 것은 바람직하지 않다.

    foo.setFull(true);   // 바람직하지 않다.
    foo._isFull = true;  // 공개 변수 역시 마찮가지로 좋지 않다.


    엑세스 함수를 남발하지 말라.

    엑세스 함수를 많이 노출해야 한다면 설계에 문제가 있다고 봐야 한다.
    이것이 나쁜 냄새다.
    가능하면 초기값이나 구현 독립적인 부분을 제외하고는 직접적인 상태 변경이 없어야 한다.
    외부에서 엑세스 함수를 최소한으로 사용하도록 설계한다.


    프러퍼티나 엑세스 함수 자동 생성 모듈을 사용하자.

    엑세스 함수가 비난받는 이유 중에 하나는 보일러플레이트 코드(boilerplate code)의 문제이다.
    데이터 접근에 별다른 동작이 필요하지 않는 경우가 대부분이다.[각주:5]
    엑세스 함수라는 규칙에 맞추려면 이러한 반복 코드를 꽤 만들어야 한다.
    이는 매우 귀찮은 작업이다.

    사실 그럴 필요는 없다.
    프러퍼티를 사용하거나,
    엑세스 함수를 자동으로 생성하는 모듈[각주:6] 을 사용하면 된다.

    C#의 프러퍼티:

    public class Date
    {
        private int year = 2017;
        public int Year { get; set; }    // 기본 getter/setter
    
        private int month = 2;
        public int Month
        {
            get { return month; }
            set    // 단순하지 않은 getter/setter
            {
                if ((value > 0) && (value < 13))
                {
                    month = value;
                }
            }
        }
    }

    Java의 Lombok 사용하기:

    public class Date
    {
        @Getter @Setter private int year = 2017; // getter/setter를 자동으로 생성
    
        @Getter private int month = 2;      // getter를 자동으로 생성
        public int setMonth(int value) {    // 단순하지 않은 setter를 별도 구현
            if ((value > 0) && (value < 13)) {
                month = value;
            }
        }
    }
    



    2018/01/17 - [Practice/Python, Perl] - 파이썬 프러퍼티 사용하여 일관되게 속성에 접근하라


    1. 프러퍼티를 제공하는 언어(C#, Python, ...)는 예외이다. 가능하면 이 언어에서는 프러퍼티를 사용한다.핵심은 섞어쓰지 않는데 있다. [본문으로]
    2. 엑세스 함수에서 사본을 생성하고 이를 반환하는 식으로 구현 [본문으로]
    3. 값을 캐싱하여 성능을 높이는 기법 [본문으로]
    4. 일관성을 유지하는 것은 매우 중요하다. 코딩 규약이나 UI 디자인 가이드 등으로 이것을 강조하는데는 이유가 있다. [본문으로]
    5. setter는 단순히 값을 복사하고, getter는 그냥 반환하면 된다. [본문으로]
    6. 자바에서는 Lombok이 유명하다. [본문으로]

    댓글 1

    • 프로필사진

      나는 응집 관점의 캡슐화 해석을 지지한다. Vector 클래스 설계법은 정보를 숨기지 않지만 이름을 가지기에 충분한 가치가 있기때문이다.
      https://justhackem.wordpress.com/2017/02/28/encapsulation-and-information-hiding/

      2017.03.02 22:12
Designed by Tistory.