자바 이벤트 만들기
(Create Java Event : C# 방식의 event 만들기)



Intro

 저는 오래전 Java 에 미쳐 있었습니다.
사실 OOP 에 미쳐있었다는게 맞을 수도 있습니다.
당시에 제 머릿속에 Java 하면 OOP 이고, OOP 하면 Java 였으니까요.

그러다 어느날 C# 을 접하게 되었고, Java 와는 멀어지게 되었습니다.
C# 은 OOP 언어이면서도, 너무 OOP 를 지킴으로써 발생되는 불편한 점을 개선한 개발자에게 너무 편한 언어였으니까요.
Java 처럼 무조건 OOP 만 따르며, 포인터 따위는 절대적으로 배제하는 그런 언어가 아닙니다. :)

아무튼 그렇게 멀어졌던 자바로 다시 개발을 해야 하는 상황이 생겼습니다.
사실 C# 과 Java 는 너무나 닮아서, 그게 불편함은 느끼지 못했습니다.

하지만 바로 자바의 이벤트 만큼은 너무나 불편했습니다. OTL
C# 은 아시겠지만, event 라는 키워드가 있어서 이벤트를 사용자가 정의하기가 너무나 쉽습니다.

예를들면,

public event EventHandler<MouseOnClickedEventArgs> MouseClicked;

이렇게 함으로써, MouseClicked 라는 이벤트를 생성할 수 있습니다.
이벤트 발생시 MouseOnClickedEventArgs 라는 객체가 전달되죠.


그런데 자바는 너무나 어렵습니다.
Observer 패턴을 직접 구현해야 합니다.
IObserver 를 상속받아서 구현해야 하고, 일이 너무나 많아집니다.

그리고 5가지의 이벤트를 만든다고 할 경우, 각각 이벤트의 Observer 를 정의하고, 만들어 주어야 합니다.
그래서 생각이 들었지요.

'C# 의 event 키워드를 대신해줄 녀석을 만들어 보자.'



Code

[Event 클래스]




[IEventHandler 인터페이스]


[EventArgs 클래스]





Analysis

이 코드의 핵심은 지네릭(Generic) 입니다.
오묘하게 타입 선언이 꼬리에 꼬리를 무는 구조로 되어 있습니다.

먼저 살펴봐야 하는 부분은 IEventHandler 클래스 입니다.
자바에서 흔히 말하는 eventListener 의 역할을 하는 class 이죠.
이벤트가 발생되었을 때, 전달되는 파라미터(EventArgs)가 지네릭(Generic)으로 되어 있습니다.
그리고 이 값은 EventArgs 를 상속받은 Class 로 한정되어 있습니다.

다음으로 Event 클래스를 살펴 봅시다.
내부적으로 이벤트 리스너(IEventHandler) 의 리스트를 가지고 있습니다.
그런데 이 리스너는 IEventHandler<TEventArgs> 로 되어 있습니다.
TEventArgs 는 Event 가 발생되었을 때 전달할 파라미터 타입으로 제한됩니다.

즉 결과적으로 보면, 아래 T 값은 모두 동일한 타입으로 제한되었다는 것을 알 수 있습니다.
Event<T> === receivedEvent(Object, T) === IEventHandler(T)

실제로 위 코드를 복사한 뒤, Event 를 만들어서 테스트 해 보시면 알게 되실 겁니다.
위 T 값은 컴파일 시점에서 반드시 모두 동일한 타입이어야만 합니다. (상속 관계 조차도 허용하지 않습니다.)
아니면 빌드시 오류가 발생합니다. 이것이 핵심이죠.
개발자의 실수를 최소화 하기 위해서, 컴파일 시점에 오류가 발생하도록 하는 것.



Test Code

[이벤트 리스너에서 이벤트 발생시 전달받을 오브젝트 클래스]

 - 이벤트 발생시, 리스너(Observer)에서 함께 전달받을 클래스
 - EventArgs 를 상속받아야 함
 - 따로 전달해 줄 정보가 없는 경우, 정의할 필요 없음


[테스트를 위해 만든 이벤트를 발생시키는 코드]
 - 중요한 코드는 "public Event<VisitedEventArgs> Visited = new Event<VisitedEventArgs>();"
 - 위 코드가 이벤트를 생성하는 코드임(이벤트 발생시 VisitedEventArgs 를 전달해주는 이벤트)

 - 이벤트를 발생시키기 위해서 아래 코드를 삽입
 - this.Visited.raiseEvent(this, new VisitedEventArgs("Michale Visited!"));
 - raiseEvent() 를 호출하고, 파라미터로 this 와 EventArgs 를 상속받은 객체를 사용


[테스트 메인]

 - addEventHandler() 를 이용하여 Observer 를 등록
 - 위 코드에서는 Observer 로 this 를 사용함
 - Observer 는 IEventHandler 를 implements 하면 됨



Result

 지네릭(Generic)은 잘 사용하면, 정말 좋은 것임에 틀림 없습니다. :)
사실 처음 코드는 현재 블로깅한 코드보다 복잡했습니다.
이중 지네릭을 사용했었거든요.
그러다가 고치고 고쳐서 지금의 코드가 만들어 졌네요.ㅎ