블로그는 나의 힘!
[ Programing ]/C++2010. 2. 24. 00:57

이전 객체지향( class )의 함수( method ) 이름 정리에 이어,
class 의 은닉( private ), 상속( protected ), 공개( public )의 효율적 사용법을 적고자 한다.

보통 간단하게는 은닉하고, 공개 한다는 것 외엔 크게 가슴에 와 닿지 않는다.
조금 생각 한다면 외부 사용이 아니라면 은닉화 시켜 버리는게 객체 작성의 미덕이다.

그러면 언제나 마찬가지로 protected 사용이 애매해 지는것.
단순히 은닉이지만 상속으로 하면 상속된 자식 클래스는 사용이 가능해 진다는 것이 전부이니 상속을 생각해서 만드는 클래스라면 사용한다고 생각할 것이다.

막상 코드를 짜 보면 상속을 고려해서 만들지는 않는다.
나중에 추가 유지 보수를 하다 보니 어쩌다 보니( 어쩔 수 없이 ) 상속을 만들게 되다 보니 사용하게 되는 기능이다.
그때 되서 부랴 부랴 기존에 있는 소스를 protected로 수정하는 방식이다.

그래서 만들기 전 미리 이 함수가 어디 까지 사용할지 판단은 만드는 사용자가 생각 하는 것이지만,
어떻게 만들어야 효율적 작성인지 적어 보고자 한다.




>>> private
내부에만 사용하는 속성. 은닉화.
특별히 외부에 공개해야 할 일이 없고 내부에서 주로 사용할 경우 이 속성을 사용한다.

예를 들면 외부에 특별히 사용하는 멤버 변수는 아니나, 값 변경이 있다. ( SetFunction() )
하지만 조건이 있어서 단순히 값 변경이 아닌 조건을 거쳐서 해당이 된다면 값이 변경이 되고,
그 조건 중 충당이 안된다면 변경이 안되거나 일부만 변경 되는 조금 복잡한 구조라면,
반드시 함수하나를 더 만들어서 주는게 좋다. 이렇게 만들어진 함수를 내부에서 동작하고 사용하기 위해 만드는 것이다.

다른 예를 들면 public에 Render( type Time )을 만들어 동적으로 돌아가게 만들어 놓았는데 이것이 다양하다면,
좀더 세분화 하여 만들고자 하는 다양해진 함수를 만들어 준다.
RenderInterface( type Time ), RenderView( type Time ) 이렇게 세분화 되어,
Render( type Time ) { RenderInterface( Time ); RenderView( Time ); } 분할하여 만들었다.

하지만 Render만 외부에서 사용하며 굳이 RenderInterface와 RenderView는 내부에서 사용할 일이 없고,
Render라는 함수에서 처리하기에 은닉화 시켜 주는것이 좋은 편이다.




>>> protected
상속되는 객체는 허용하는 속성.
이론 상으로는 상속이 되는 클래스만 부모가 가진 자원을 물려 주기 위해 만들어진 속성이지만,
정작 코드를 만들다 보면 의도적으로 만들지 않는 이상 특별히 상속을 만들일이 없다.

하지만 사람일이라는게 모르는 걸 보여주듯 꼭 작업 하다 중간에 만들어야 하는 상황이 가끔 생길때가 있다.
이러면 중간에 코드가 애매해져 버리는데, 그런 경우를 대비해서 만드는 사용자가 이건 민감한 사항이 아니고,
그렇다고 외부 공개로 사용자가 조작하게는 하기 싫다면, 추후 상속을 대비 하기 위해 protected에 확장성을 고려해서 만둘어 주는 것도 좋은 사항이다.

private에서 만들 당시 특별히 외부 사용이 없으니 내부에서만 돌아가게 호출만 하면 해당 조건이 실행 되도록 만들어 놓으면 되나, ( SetFunction() ) protected에서 만든다면 private와 비슷하게 동작처리는 하나 자식에서도 어느 정도 제어가 가능하게 인자 값을 설정 할 수 있도록 만들어 주는 것이 좋다. ( SetFunction( type Data ) )

예를 들어 부모 클래스에
private는 내부에서 사용하기에 이렇게 설정이 되어 외부 해당 사항에 맞게 동작이 되어 진다면,
class High
{
   bool Event;
   long int Index;

private:
   void SetIndex() { if( Event ) Index += 5; }

public:
   High() {}
   ~High() {}
}


추후 확장성을 고려 하여 protected로 작성하였다면 비슷하게 작성하나 자식에서도 어느 정도 설정이 가능하도록
class High
{
   bool Event;
   long int Index;

protected
   void SetIndex( long int Value ) { if( Event ) Index += Value; }

public:
   High() {}
   ~High() {}
}


이렇게 작성하여 함수도 마찬가지로 확장성이 고려하여 작성 하는 것이 좋다.




>>> public
외부 공개되는 속성.
사용자가 만든 클래스 중 외부에서 사용하라고 지정된 함수( 간혹 변수 )를 지정하는 속성이다.
보통 멤버 변수의 값을 변경하여 설정 값이나 동작을 바꾸는 함수나 ( SetFunction( type Data ) ),
멤버 변수의 값을 받아와서 그 해당 이벤트 처리를 위해 가져 오는 함수 ( type GetFunction() ),
그리고 동적으로 처리해야하는 함수 ( Process( type Time ), FrameMove( type Time ), Render( type Time ) ),
생성&해제, 초기화를 위한 함수 ( Initialize(), Release(), Clear() ) 를 보통 외부 공개하여 컨트롤 할 수 있게 한다.

최대한 복잡하지 않게 사용자가 단순히 설정 값만 바꿔도 동작 처리가 가능하게 하도록 만드는 것이 좋다.
그러면 동시에 사용자 편의성이 올라가고, 직관적이며, 단순하면서 강력한 기능이 지원하는 class가 만들어 진다.

세탁기를 예를 들면,
콘센트를 꼽아 ( Initialize() ),
전력을 공급하고 ( Process( type Time ), FrameMove( type Time ), Render( type Time ) ),
버튼을 눌러 이불 빨래 인지 옷 빨래 인지 선택 하고 ( SetFunction( type Data ) ),
세제를 얼마나 넣어야 하는지 확인하고 ( type GetFunction() ),
이불 빨래 인데 잘못 하고 옷 빨래로 설정 했을 경우 초기화 해주고 난후 ( Clear() ),
재설정해 ( SetFunction( type Data ) ) 동작 ( SetFunction() ) 시키고,
빨래가 끝나면 콘센트를 뽑고 ( Release() ),
정리 하면 되는 것이다.

사용자에게 빨래를 위한 것에 최대한 지원 해 주면 되는 것일 뿐...
복잡하게 모터가 어떻게 동작하는 지, 물이 어떻게 들어가서 나와야하는 지 알빠 아니다.
만약 이런 처리를 사용자가 할 경우 최악의 제품이 되는 것이다.

클래스가 만약 이런 처리를 본인이 만든 클래스가 다른 사람이 밖에서 조건을 걸어서 사용할 수 밖에 없고,
그렇게 동작하게 만들어야 한다면 객체지향이라는 껍데기만 덮어 씌어져 있을 뿐, 최악의 객체지향이다.

최대한 사용자는 단순히 버튼만 눌러서(제시된 함수만으로) 동작하게 복잡하지 않고 간단하게 만드는 것이 중요하다.
( 근데 이게 생각보다 난이도가 높은 편이다. )

E.X. )

♣ ♣ ♣ 객체지향적 코드 ♣ ♣ ♣

class WashingMachine {}

void main ()
{
   double PassTime = 0.0f;    // 프레임 시간 값 받기

   WashingMachine cWM;

   // 사용자는 단순히 몇가지 설정만 해주고
   cWM.SetChoice( "shirt" );
   cWM.SetStart();

   while( cWM.GetExit() )
   {
      PassTime = FrameTimer();

      // 동적으로 동적하게 환경만 제공해 준다면
      // 해당 클래스는 동작이 되게 만든다면 최상의 객체 지향적 코드
      cWM.FrameMove( PassTime );
      cWM.Render( PassTime );
   }
}



♣ ♣ ♣  비객체지향적 코드 ♣ ♣ ♣
class WashingMachine {}

void main ()
{
   double PassTime      = 0.0f;    // 프레임 시간 값 받기
   long int RenderValue = 0;

   WashingMachine cWM;

   cWM.SetChoice( "shirt" );
   cWM.SetStart();

   while( cWM.GetExit() )
   {
      PassTime = FrameTimer();

      // WashingMachine를 사용하는 사용자가 세부 설정을 조작해야 하는 불상사가 생긴다.
      // Class화 하는 의미가 없는 비효율적 객체지향 코드라고 볼 수 있다.

      if( cWM.FrameMove( PassTime ) )   RenderValue = cWM.Render( PassTime );
      if( 1 == RenderValue )  SetMotorCycle( true );
      if( GetWater() )   SetWater( 100 );     
   }
}

'[ Programing ] > C++' 카테고리의 다른 글

Function pointer  (0) 2010.07.01
C++ Debugging  (0) 2010.06.25
Function & Method Name 정리  (0) 2010.02.18
전처리문의 종류(#include, #define, #ifdef, ... )  (1) 2010.02.10
[ reinterpret_cast ] 그 강력함을 알고 쓰자.  (0) 2010.02.04
Posted by Mister_Q