본문 바로가기

IT 살이/04. 기술 - 프로그래밍

이벤트 핸들링 패턴

요즘은 달봉이가 맡았던 업무를 전산실 직원에게 백업을 하는 것이 주요 하루 일과다. 오늘 백업도중 어쩌다 .NET의 이벤트 핸들링 패턴에 대한 얘기가 나왔었다. 예전에 달봉이가 처음 이벤트를 배울려고 했을때 잘 이해하지 못했던 부분이 있었는데, 생각난 김에 함 정리를 해 볼려고 한다.

우리는 어떤 이벤트를 이용하기 위해서 사용하는 방법에 대해서 알고 있다.
- 이벤트( 멤버)에 이벤트 핸들러를  등록하거나
- 또는 해당 이벤트 On이벤트 메소드를 오버라이드하기

이 두 방법의 차이점은 무엇일까? 이 두 방법을 모두 이용할 수 있는 것은 .NET의 이벤트 핸들링 패턴 때문이다. 다음 코드는 이벤트 "Loaded"라는 것을 정의해서 이 이벤트에 대한 핸들링을 하는 두 방법을 보여주고 있다. 다시 한번 상기시키면 다음 코드는 개발자가 작성하는 코드이다.


 
public class DerivedControl : BaseControl
  {
     
public DerivedControl()
      {
         //이벤트 핸들링 방법 2.1
         
this.Loaded += new LoadedEventHandler(this.LoadedEventHandler);
     
}
     //이벤트 핸들링 방법 1
     
protected override void OnLoaded(EventArgs e)
      {
         
//이곳에서 필요한 작업을 한다.

          //베이스의 OnLoaded()를 호출한다.
         
base.OnLoaded(e);
     
}
      //이벤트 핸들링 2.2
     
private void LoadedEventHandler(object sender, EventArgs e)
      {
         
//이곳에서 필요한 작업을 한다.
     
}
  }

개발자가 DerivedControl을 가지고 작업을 할때 이벤트 핸들링 1 방법을 사용해도 되고 2 방법을 사용해도 된다. 

이벤트 핸들링 1 : On메소드 오바라이딩 사용.
이벤트 핸들링 2 : 이벤트 핸들러 사용

이벤트 핸들러를 사용하는 방법은 2.1과 2.2 가 필요하다. 즉 핸들러 메소드를 제작(2.2)해야 하고  이 핸들러를 해당 이벤트에 등록(2.1)해야 한다.

이벤트 핸들러를 사용하는 것에 대한 더 이상의 얘기는 하지 않겠다. 여기서는 On메소드 오버라이딩 방법을 사용했을 경우 어떻게 이 DerivedControl.OnLoaded() 메소드가 호출되는지를 알아볼 것이다. 그러기 위해서는 베이스 클래스 BaseControl의 구조를 머리에 그릴 수 있어야 한다.  지금부터 함 BaseControl을 그려보자.

 
//Loaded이벤트용 델리게이트 정의
  
public delegate void LoadedEventHandler(object sender, EventArgs e);

  
//베이스 클래스
  
public class BaseControl  : System.Windows.Forms.UserControl
   {
       //이벤트 멤버 : Loaded
      
public LoadedEventHandler Loaded = null;
       protected virtual void
OnLoaded(EventArgs e)
       {
          
if (Loaded != null)
           {
              //이벤트 발생
               Loaded(
this, e);
          
}
       }
   }


베이스 클래스 BaseControl에는 이처럼 이벤트 Loaded와 그것을 호출하는 가상 메소드 OnLoaded()가 정의되어 있을 것이다.

.NET 이벤트 발생 패턴에서는 직접 Loaded를 호출하는 대신에 이렇게 On이벤트 메소드를 제공해서 이 메소드내에서 이벤트를 호출하도록 하고 있다.

컨트롤이 로딩되고 나서 프레임워크쪽 또는 BaseControl쪽의 어디에선가 Loaded 이벤트를 발생시키기 위해서 OnLoaded()를 호출하게 된다. 예를 들어 다음과 같은 코드가 있을 수 있다.

private void BaseControl쪽의메소드(...)
{
....
//이곳은 BaseControl쪽 코드
this.OnLoaded(e);  // 순전히 예를 위한 호출이다.
}


이제 개발자가 다음과 같은 코드를 작성했다고 보자.

BaseControl ctrl = new DerivedControl();
윈폼객체.Control.Add(ctrl);

이렇게 생성된 컨트롤 ctrl을 윈폼이나 컨테이너 컨트롤에 Add 시켜서 로딩시켰다고 하자. 그리고 Loaded 이벤트를 발생시켜야 하는 시점에서 즉 BaseControl쪽의메소드() 내부에서 this.OnLoaded(e) 호출했다고 하자. BaseControl의 OnLoaded()가 호출될까?

BaseControl.OnLoaded()가 호출되는 것이 아니라 DerivedControl.OnLoaded()가 호출된다. this가 가리키는 것은 new DerivedControl() 객체이기때문이다.

즉 우리가 원하는 이벤트 핸들링이 이뤄진것이다.

호출되는 DerivedControl.OnLoaded()의 내용을 보면 코드에서처럼 그곳에서는 다시 베이스의 OnLoaded()를 호출해야 한다.

//베이스의 OnLoaded()를 호출한다.
base.OnLoaded(e);


이 메소드를 호출해야 base.OnLoaded()에서 Loaded 이벤트를 호출해서, 다른 곳에서 Loaded에 등록했을지도 모를 다른 핸들러들을 실행시켜야 하기 때문이다.

따라서 메소드 실행 순서를 정리해보면 다음과 같다.

DerivedControl.OnLoaded() -> BaseControl.OnLoaded() -> Loaded 이벤트 핸들러

이벤트 핸들링 하는 방법으로 On메소드을 오버라이딩하는 것과 이벤트 핸드러를 사용하는 것에 대해서 알아봤다.

다 써놓고 보니까 또 내가 이것을 왜 썼나 싶다.-_-;; 히잉~