방프리

23.08.20 Chapter2. API 설계 (Item 21) 본문

C#/More Effective C#

23.08.20 Chapter2. API 설계 (Item 21)

방프리 2023. 8. 20. 23:08

Item 21 : 이벤트는 가상으로 선언하지 말라

 

이벤트를 가상으로 선언할 경우 결합도가 더 강해진다. 가상으로 선언할 경우 파생 클래스에서만 사용 가능하거나

베이스 클래스에서만 사용 가능한 선택 영역으로 빠지기 때문이다.

결합도를 낮추기 위해 사용했던 것이 오히려 결합도를 강하게 만들어버린 상황이 오게 된다.

이 경우 저자는 두 가지 해결책을 제시하였다.

1. 가상 이벤트를 만들 때 필드 정의 방식으로 이벤트를 정의하지 않는 것

2. 가상 이벤트 정의를 생성할 때마다 이벤트를 발생시키는 가상 메서드를 만드는 것

하단의 코드는 2번 해결책을 응용한 코드이다.

public abstract class WorkerEngineBase
{
    public virtual event EventHandler<WorkerEventArgs> OnProgress;
    
    protected virtual WorkerEventArgs RaiseEvent(WorkerEventArgs args)
    {
    	OnProgress?.Invoke(this, args);
        return args;
    }
    
    public void DoLotsOfStuff()
    {
    	for (int i = 0; i < 100; ++i)
        {
        	SomeWork();
            var args = new WorkerEventArgs();
            args.Percent = i;
            RaiseEvent(args);
            if (args.Cancel)
            return;
        }
    }
    
    protected abstract void SomeWork();
}

public class WorkEngineDerived : WorkerEngineBase
{
    protected override void SomeWork()
    {
    	Thread.Sleep(50);
    }
    
    public override event EventHandler<WorkerEventArgs> OnProgress;
    
    protected override WorkerEventArgs RaiseEvent(WorkerEventArgs args)
    {
    	OnProgress?.Invoke(this, args);
        return args;
    }
}

이 코드도 이벤트 자체만 재정의 해서는 올바르게 동작하지 않는다. 대신 이벤트를 일으키는 가상 메서드를 재정의하여

정상적으로 동작시킬수는 있다. 단 이 경우도 결합도가 낮다고 하기엔 조금 모호하다.

Comments