{

여기서 잠깐, 비공용이란 private 을, 공용이란, public 을 의미 하며, 가상이란 virtual 함수, 비가상이란 non virtual 를 뜻한다.

난 사실 이 제목데로 하는것에 마음에 와 닿지 않는다. 실제로 이렇게 구현 하려고 노력했지만, 경험상 다른 사람들이 봤을 때 익숙치 않아, 가독성이 떨어진다는 의견이 많기 때문이다. 물론 여기에 나 또한 포함 된다. : ) 이 가독성은 익숙치 않기 때문일지도 모른다. 이런 생각 때문에 나는 이것을 놓치기 싫어서, 다른 사람들의 자료를 찾기 시작했고, 정리를 하였다.

기본 예제


이 내용을 말로 풀이하자면, 참새가 A 지역으로 난다. .. 뭐 더 할말도 없고 ㅋ 여튼, 이런 참새를 보고 분석해보니, 참새는 먹이가 있는 곳으로만 날아가고, 먹이가 없다면 날아가지 않는 것을 알게 되었다. 이것을 구현하기 위해서 Fly함수 내부에 __pWhere 이 먹이가 없다면 날지 않겠다. 라고 만들어야 할 것이다.

그 구현


이렇게 먹이가 없는 지역이면 날지 않게 만들었다. 시간이 지나서 비둘기도 만들게 되었고, 비둘기 역시 먹이가 없는 지역으로는 날지 않는 것을 알게 되었고, 참새의 Fly 처럼 비둘기의 Fly를 만들려고 했지만, 이것을 잊었고, 비둘기는 먹이가 있건 없건 무조건 날기 시작했다.

나는 이 사실을 뒤늦게 깨달았고, 비둘기의 Fly를 뜯어 보면서 비둘기에게 해당 if문을 넣어 주었다. 시간이 지나자 참새나 비둘기는 날아갈 수 있는 곳을 판정하는 방법이 서로 달랐고, 다른 새들 역시 그러했다. 나는 이 사실 그대로, 해당 기능마다 Fly를 수정해 주었다. 가끔 까먹고 구현해 주지 못한 것도 있었지만, 내 잘못이려니 하고 그냥 넘어갔다.

뒤 늦게 나는 이 것이 몹시 불편하다는 것을 알게 되었다.

불편한 점
1. 가끔 까먹고 Fly에 구현해야 할 것을 잊어 먹으면 바로 버그가 된다는 점
2. 항상 흐름을 기억하고 그 흐름대로 Fly를 구현 해야 한다는 점
3. Fly의 내부 구현이 점점 복잡해 질 수 있다는 점

그래서 다음과 같이 불편한 점을 해결했다.


다음과 같은 불편한 점을 수정하였다.
1. 가끔 까먹고 Fly에 구현해야 할 것을 잊어 먹으면 바로 버그가 된다는 점
  ① 까먹고 잊어 먹는 것을 순수 가상 함수로 만들어, 상속 받는 녀석은 반드시 구현하라고 강요하면서 해결함
 
2. 항상 흐름을 기억하고 그 흐름대로 Fly를 구현 해야 한다는 점
  ① Fly에는 흐름만 제어해서 굳이 기억하지 않도록 한다.
  ② Fly를 public 함수로 만듬으로써, 흐름을 바꾸지 말라고 강요 할 수 있다.
 
3. Fly의 내부 구현이 점점 복잡해 질 수 있다는 점
  ① 상세구현을 함수로 뺌으로써, 복잡함을 각개격파 하여, 보다 보기 편하게 되었음

이렇게 하고 나니, 산뜻한 마음 코딩할 수 있게 되었다. 그런데 이렇게만 해도 좋을까?

시간이 지나자 문제가 생겨 버렸다. can_I_fly_to() 함수가 public이다 보니, 이 클래스를 사용 하는 개발자가 이 함수를 다른 용도로 사용하기 위해서 수정을 하게 되었고, 본래의 정책과 다르게 사용됨으로써, 의미를 파악할 수 없는 코드가 되고야 만 것이다. 나는 이 문제를 뒤늦게 깨달았다.

불편한 점
1. can_I_fly_to() 가 public 이여서 다른 용도로 쉽게 사용 형태가 변할 수 있다.

이것의 해결 방법으로는
① can_I_fly_to()를 private 으로 만듬으로써, 용도가 쉽게 변할 수 없게 만든다.

휴~ 여기까지 설명 된 이야기가 바로 NVI 패턴이다.


NVI 패턴 요약

1. 기반 클래스가 자신의 정책을 파생에게 강요 할수 있고, 이것으로 더 확고한 디자인이 만들어 지게 된다.
2. Non Virtual Interface 함수로 인하여, 흐름을 보다 자연스럽게(이 흐름을 재정의 못하게 함으로써) 만들어 준다.
3. 다른 개발자에게 무엇을 변경해도 되는지 보다 쉽게 알 수 있게 해 준다.(정책을 봄으로써)
4. 기반 클래스의 변화에 파생 클래스의 수정이 보다 쉬워진다. (정책의 강요로 인하여)

관련 링크

http://yesarang.tistory.com/281
http://ideathinking.com/blog-v2/?p=48
http://www.memorycarrier.com/old_www/y2k2/nvi.html
http://ikpil.com/812
http://kldp.org/node/75867

}

'책 정리 > C++ Coding Standards : C++ 코딩의 정석' 카테고리의 다른 글

항목 44 : 비멤버 함수를 활용하라. ( Prefer writing nonmember nonfriend functions. )  (0) 2009.03.31
항목 43 : Pimpl을 적당히 활용하라. ( Pimpl judiciously. )  (0) 2009.03.31
항목 42 : 내부의 것은 너무 노출시키지 말라. ( Don’t give away your internals. )  (0) 2009.03.31
항목 41 : 특징 없는 값의 집합을 제외하고는 모든 데이터 멤버를 사영으로 하라. Make data members private, except in behaviorless aggregates (C-style structs).  (0) 2009.03.31
항목 40 : 간접 변환을 피하라. ( Avoid providing implicit conversions. )  (1) 2009.03.30
항목 39 : 가상 함수는 비공용으로, 공용 함수는 비가상으로 설정하라. ( Consider making virtual functions nonpublic, and public functions nonvirtual. )  (0) 2009.03.30
항목 38 : 안전한 오버라이딩을 연습하라. ( Practice safe overriding. )  (0) 2009.03.02
항목 37 : 상속의 정확한 의미를 이해하자. 재사용을 위해 상속하는 것은 아니지만, 재사용은 필요하다. ( Public inheritance is substitutability. Inherit, not to reuse, but to be reused. )  (0) 2009.03.02
항목 36 : 추상 인터페이스를 활용하라. ( Prefer providing abstract interfaces. )  (0) 2009.03.02
항목 35 : 기반 클래스로 디자인되지 않은 클래스로부터의 상속을 피하라. ( Avoid inheriting from classes that were not designed to be base classes. )  (0) 2009.03.01
항목 34 : 상속성을 주의해서 사용하라. ( Prefer composition to inheritance. )  (0) 2009.02.28
posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요