-
엑세스 함수(getter/setter)를 올바로 사용하기Programmer/Programming 2017. 2. 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의 무분별한 노출은 객체의 구현과 상관없이 객체의 상태를 직접 변경할 수 여지를 줄 수 있다.
공개 변수 사용은 당연히 좋지 않고, getter/setter도 가능하면 적게 공개하여 이런 문제를 방지해야 한다.
예를 들어 설명하겠다.
밥을 먹으면 배부른 상태가 되어야 한다.
foo.eat(); assert(foo.isFull() == true);
반면, 객체 밖에서 배부른 상태를 직접 변경하는 것은 바람직하지 않다.
foo.setFull(true); // 바람직하지 않다. foo._isFull = true; // 공개 변수 역시 마찮가지로 좋지 않다.
엑세스 함수를 남발하지 말라.
엑세스 함수를 많이 노출해야 한다면 설계에 문제가 있다고 봐야 한다.
이것이 나쁜 냄새다.
가능하면 초기값이나 구현 독립적인 부분을 제외하고는 직접적인 상태 변경이 없어야 한다.
외부에서 엑세스 함수를 최소한으로 사용하도록 설계한다.프러퍼티나 엑세스 함수 자동 생성 모듈을 사용하자.
엑세스 함수가 비난받는 이유 중에 하나는 보일러플레이트 코드(boilerplate code)의 문제이다.
데이터 접근에 별다른 동작이 필요하지 않는 경우가 대부분이다. 5
엑세스 함수라는 규칙에 맞추려면 이러한 반복 코드를 꽤 만들어야 한다.
이는 매우 귀찮은 작업이다.사실 그럴 필요는 없다.
프러퍼티를 사용하거나, 엑세스 함수를 자동으로 생성하는 모듈 을 사용하면 된다. 6C#의 프러퍼티:
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] - 파이썬 프러퍼티 사용하여 일관되게 속성에 접근하라
'Programmer > Programming' 카테고리의 다른 글
일단 만들어라. 두 번 만들어라. 그러면 보일 것이다. (0) 2017.06.29 문제가 발생하면 근본 원인 찾아라. (1) 2017.03.06 public, private, const 키워드가 필요한 이유 (1) 2017.02.08 C언어에서 struct 정의 그대로 이진 데이터로 만들기 (0) 2017.01.13 교착상태(deadlock)를 프로세스 상태와 디버거를 사용해서 찾아내기 (1) 2017.01.06 댓글