블로그 이미지
내게 능력 주시는 자 안에서 내가 모든것을 할수 있느니라 - 빌립보서 4 : 13 - happydong

카테고리

Happydong (1363)
프로그래밍 (156)
MUSIC (16)
인물 (3)
Utility (10)
세미나 소식&내용 (22)
IT뉴스 (18)
운동 (830)
CAFE (10)
Life (282)
Total
Today
Yesterday





 
옵저버 패턴(Observer pattern) 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 연락을 주고, 자동으로 해당 객체들의 내용이 갱신이 되도록 하는 방식으로 일대다(ont-to-many) 의존성을 정의 한다. 일반적으로 분산 이벤트 처리를 목적으로 많이 사용한다고 한다. 아래는 예제로 보여줄 옵저버 패턴의 클래스 다이어그램(Class diagram)과 프로젝트 파일들을 나타낸 것이다.
(참고로 현재 예제코드는 윈품(WinForm)프로젝트로 만들어 보았다. )


 위 그림에 보면, 3개의 인터페이스(Interface)가 있고, 이 인터페이스 상속받아 구현한 객체가 있다. 좀더 자세히 보면 CountObserverCenter라는 녀석은 IObserverCenter 인터페이스를 상속 받아 구현되었다. 그리고 Screen1, Screen2는 IScreen 인터페이스를 상속받아 구현되었으며, IObserver 인터페이스를 상속 받아 구현되었다. (C#에서는 인터페이스 다중 상속이 된다는 걸 알고 있을 것이다.) Screen1과 Screen2는 UserControl이다. 그럼 각각의 객체의 역활및 소스코드에 대해서 알아 보도록 하겠다.

1. IObserverCenter와 CountObserverCenter

 - IObserverCenter는 Observer들의 추가, 삭제, 알림 기능을 할 수 있는 인터페이스만 정의 되어 있다.



 - CountObserverCenter는 IObserverCenter 인터페이스를 상속받았으므로, 추가,삭제, 알림 기능을 하는 메소드를 구현해 준다. 즉, 실질적으로 작동이 되도록 정의하는 것이다. CountObserverCenter의 역활은 특정 액션이 전달되면 각각의 Observer들에게 카운트를 증가시키라는 알림을 알려주는 역활을 하는데, 이는 _count와 _observerLIst 맴버를 이용하게 된다. 아래 소스를 보면 이해하기 쉬울 것이다.



2. IObserver와 IScreen 그리고 Screen1,Screen2

 - IObserver는 옵져버 센터에서 연락을 받을 수 있는 인터페이스만 정의 되어 있다. 다시말해 NotifyAction메소드를 통해서 알람 내용을 정의 할수 있는 것이다.



 - IScreen은 Screen1,Screen2가 공통으로 정의될 내용의 인터페이스가 정의 되어 있다. UpdateScreen 메소드를 통해서 해당 Screen의 내용이 갱신되도록 정의한다.



 - Screen1과 Screen2는 UserControl로서 IOserver 인터페이스와 IScreen 인터페이스의 내용을 상속받아 동작 내용을 정의 한다. 즉, IOserver 인터페이스의 NotifyAction 메소드가 호출되었을 때 작동해야할 내용을 정의하며, IScreen 인터페이스의 UpdateScreen 메소드가 호출되었을 때 내용을 정의 한다. (코드 설명은 주석을 참고 하기 바란다.)




위 그림은 Screen1과 Screen2의 디자인 모습인데, 간단하다. Panel Control 위에 Label Control를 올려 놓은 것이다. 그리고 소스는 Screen1에 대해서만 올려 졌는데, 그 이유는 Screen2또한 같은 소스 코드기 때문에 생략 한 것 이다.

자 그럼 위 내용 처럼 ObserverCenter와 Obsever가 준비되 었다면, 메인 폼(Form)에서 내용을 정의하고 실행 시켜보도록 하겠다. 우선, 메인 폼에 대한 디자인 모습은 아래와 같다.



간단한 디자인이다. 샘플이므로... 버튼이 하나 올려져 있는데, 이 버튼을 클릭할때 마다 Screen1과 Screen2의 Count를 증가 시켜줄 것이다. 그리고 SplitContainer Control이 있는데, 이는 Screen1과 Screen2를 올려 놓을 컨테이너이다. 그럼 폼의 코드를 살펴 보자.



폼에서는 간략하게 생성자에서 유저컨트롤들의 인스턴스를 생성해서, 추가시켜주는 내용과 버튼 이벤트를 받아서 알림 액션을 처리하는 내용 뿐이다. 생성자에서 CountObserverCenter를 인스턴스로 생성을하고 Screen1과 Screen2의 파라미터로 넘겨 주는 데, CountObserverCenter는 참조타입(Reference type)이기 때문에 객체의 주소값이 넘어 가게 된다. 이를 Screen1,2에서 받아서 맴버로 가지고 있기때문에 알람 액션에 대한 내용 전달 받을 수 있고, 처리할수 있는 것 이다.

해당 예제소스는 첨부파일로 첨부되어 있다. 다운 받아 확인 할수 있을 것이다.

Posted by happydong
, |



몇일 전에 같이 일하는 분이 우리가 진행중인 프로그램에 UserControl부분을 개발하고 있었다. 그런데 그분이 코드에서 빌드는 잘되고, 에러는 없는데, 폼(Form) 디자인 모드에서 자신이 만들 컨트롤을 드래그해서 넣으면 에러가 난다는 것이었다. 빌드를 해도 이상이 없고, 내가 코드를 보니 특별히 이상한 부분은 없었다. 허나, 생성자 부분에서 특정 XML을 로드하는 로직이 들어 있었다. 알고 보니, 이 부분때문에 폼에서 해당 컨트롤을 넣으면 문제가 되는 것이었다. 폼 디자인모드에서 파일을 읽어 오거나 할수 없기때문에, 당연히 에러가 나는게 맞다!! 그럼 이런 문제를 해결할 방법은 있는가? 있다!! 아래 소스와 같이 구분해주면 된다.

         public Main()
        {
            InitializeComponent();

            // 디자인 모드인지 확인하는 내용입니다.
            if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
            {
                System.Diagnostics.Debug.WriteLine("DesignMode");
            }
        }


이상 윈폼 디자인모드 확인하는 방법 이었다!!
Posted by happydong
, |



 C#으로 개발을 하다보면 다양한 상황에서 디버깅을해서 처리 값을 확인해야 하는 일이 생긴다. Output Value를 확인하다든지... 정확한 값이 세팅되었다 든지..., 더미값(쓰레기값)을 세팅해서 프로그램을 테스트 한다던지... 등등의 여러가지 상황에서 디버깅 값을 확인해야 할 일들이 빈번하게 있기 마련이다. 그리고 이렇게 디버깅한 내용은 릴리즈 할때는 적용이 안되어야 하는 것이 맞다. 그래서 디버깅 코드를 짤때에는 디버그모드일때와 릴리지모드일때 실행되야할 코드를 적절히 나눠서 짜야한다. 이렇게 구분하기 위해서는  #if #endifConditional Attribute를 적절하게 사용하는 것이 좋다. 

처음 개발을 시작했을 때는 생각해보자!! 예전 같았으면 프로그램 소스를 짜면서 디버깅소스를 코드로 같이 짜고 디버그 모드(Debug Mode)에서 확인하고 필요없을때(릴리즈때)는 주석처리하면서 했을 것이다. 물론, 머리가 좋은 사람들은 이런식으로 처리안 했을 것이다. 그러나 프로그램을 처음 접하면서 배우는 것이 디버깅하는 방법보다, 주석을 먼저 배우기때문에 이런 불편한 방법을 사용하는 초보 개발자들이 몇몇 있을 것이다. 물론, 나도 처음 배울때 이랬다.

주석으로 처리하는 잘못된 예

 /*  릴리즈때는 사용하지 않음.
            MessageBox.Show("Test");
  */

위 코드의 내용 처럼 릴리즈 모드(Release Mode)일때와 디버그 모드(Debug Mode)일때를 확인해서 처리해야하는 경우가 있다면 바보같이 주석처리해가면서 처리하지말고 #if #end와 Conditional Attribute를 이용하자!!

1. #if #endif 사용

 이는 메소드 내부의 간단한 처리를 확인 할때 사용하는 것이 적절한 것 같다. 사용 방법은 아래와 같다.

#if #endif

 private void InitializeView()
        {

#if DEBUG
            // 처리된 결과의 값을 찍어 봅니다.
            Debug.WriteLine("Value1");
            Debug.WriteLine("Value2");
#endif
        }

#if #endif를 많이 사용하면 코드가 조금 지저분해 질수 있으니 적절하게 적당히 사용하는 것이 좋을 것 같다.  

 

2. Conditional Attribute 사용

이는 메소드 형태로 사용할수 있으면 빌드모드에 따라 해당 메소드를 호출할지 않할지를 결정할수 있다. 사용 방법은 아래와 같다.

Conditional Attribute

private void InitializeView()
{
      ... 내용 생략...
      DebugMsg();
}

[Conditional("DEBUG")]
public void DebugMsg()
{
      MessageBox.Show("Conditional Test");
}

InitializeView메소드안에 보면 DebugMsg라는 메소드를 호출하고 있는데, 빌드모드가 디버그이면 해당 메소드를 호출할 것이고, 릴리즈일 경우 호출되지 않을 것이다. 그리고 Conditional은 다중 지정이 가능하다. 즉, [Conditional("DEBUG"), Conditional("TRACE")] 이런식으로 가능하다.

#if #endif와 Conditional Attribute를 적절히 사용하면 보다 깔끔한 코드, 디버그모드와 릴리지모드를 나눠서 코드를 정리할수 있을 것이다. 물론, #if #endif보다는 Conditional Attribute를 활용하는 쪽이 보다 깔끔한 소스를 짤수 있을 것이다. Conditional를 선언한 메소드들을 한클래스에 모아서 사용하는 것도 적절하다 볼수 있다.

 참고 )
프로젝트의 프로퍼티(Properties)메뉴에 들어가, 빌드(Build) 옵션에서 해당 빌드모드의 내용을 체크할수 있다.

Posted by happydong
, |