Posts tagged 확장 메서드
인터페이스와 확장메서드의 활용
8 2nd
기본적으로 다중 상속을 지원하지 않는 C#의 디자인때문에 인터페이스 상속을 이용해 다중상속을 구현해왔습니다. 이와 관련한 내용으로 오래전부터 포스팅해야 겠다는 생각만 했을 뿐 실천을 하지 못하던 중 여유가 생겨 정리해 봅니다.
위 코드에서 보듯 Java와 마찬가지로 C# 역시 여러 클래스를 동시에 상속할 수 없습니다. 따라서 Java와 동일한 방법으로 인터페이스를 이용하여 이러한 결과를 얻을 수는 있습니다. 하지만 인터페이스는 메서드 시그니쳐가 포함되어있을 뿐 구현이 포함되어있지 않습니다. 인터페이스는 상수, 필드, 생성자, 소멸자, 모든 형식의 정적멤버를 포함할 수 없습니다.
따라서 C#에서 여러개의 클래스를 상속하고자 한다면 반드시 인터페이스를 이용해야 하고, 그 구현부는 상속받은 클래스에서 구현되어야 합니다.
이 예에서는 보여드리는 클래스인 FiscalizacionDetailBase라는 클래스는 전자결제를 사용하기 위해 IElectronicApproval을 상속하고 있습니다. 하지만 또다른 RegisterFrm이라는 클래스는 이력관리를 위한 IHistoryManagement를 상속하고 있습니다. 모두 같은 FormBase라는 슈퍼클래스를 상속하고 있습니다.
따라서 각 기능에 해상하는 상속을 구현하기 위해(=다중 상속을 이용하기 위해) 각기 다른 인터페이스를 상속받고 있습니다.
하지만 C# 3.0부터 지원하는 확장 메서드를 이용한다면 무척 편리하게 구현이 가능합니다. (물론 개발자 입장에서 구현의 편리함을 강조하는 것입니다.)
이 예에서는 전자결제에서 사용하고자 하는 매개변수들과 이력관리에서 사용하는 매개변수가 다릅니다. 때문에 해당 인터페이스에 해당하는 구현부를 각각의 클래스들에서 구현했었어야 합니다. 물론 객제지향개발 방법론에 의하면 올바른 구현이 아닙니다.
이를 OOP의 가르침대로 구현하려면 먼저 FormBase가 각 인터페이스를 상속하고, FormBase에서 인터페이스를 구현했었어야 합니다. 그 이후 FormBase를 상속하는 클래스에서는 필요한 인터페이스를 상속하여 구현된 시그내처를 사용하는 것입니다. 그러나 이렇게 구현을 했을 경우 지나치게 FormBase가 무거워질 수 있습니다. 사용하지 않는 불필요한 구현부가 있기 때문이지요. OOP에 대해 이야기 한다는것 자체가 꽤 진부하니 OOP이야기는 여기서 마무리하지요.
이야기하고 있는 인터페이스는 다음과 같이 디자인 했습니다.
1: public interface IElectronicApproval : IHistoryManagement
2: {
3: Enum.ButtonMode eButtonMode { get; set; }
4: string BizDocType { get; }
5: string CurrentSaveFlag { get; set; }
6: string CurrentStatusCode { get; set; }
7: decimal CurrentVersion { get; set; }
8: string HoldingResult { get; set; }
9: string ExistResult { get; set; }
10: string ScreenName { get; set; }
11: string Language { get; set; }
12: }
1: public interface IHistoryManagement
2: {
3: Enum.UIMode eUIMode { get; set; }
4:
5: string RegisterCode { get; set; }
6: string RegisterLocation { get; set; }
7: string UpdaterCode { get; set; }
8: string UpdaterLocation { get; set; }
9: DateTime RegisterDate { get; set; }
10: DateTime UpdateDate { get; set; }
11: DateTime EffectiveDate { get; set; }
12: }
보다시피 각 인터페이스는 메서드 시그내쳐는 없습니다. 다만 프로퍼티들만 존재할 뿐입니다.
이에 필요한 메서드는 확장메서드를 이용해 구현합니다. 다음과 같이 말이죠.
1: public static void SetApprovalRequiredParameter(this IElectronicApproval electronicApproval, RequestParameter rParam)
2: {
3: rParam.Add("BizDocType", electronicApproval.BizDocType);
4: rParam.Add("SaveFlag", ((ushort)electronicApproval.eButtonMode).ToString());
5:
6: rParam.Add("CurrentSaveFlag", electronicApproval.CurrentSaveFlag);
7: rParam.Add("CurrentStatusCode", electronicApproval.CurrentStatusCode);
8: rParam.Add("CurrentStatusCode1", GetStatusCode1(electronicApproval.CurrentStatusCode));
9: rParam.Add("CurrentStatusCode2", GetStatusCode2(electronicApproval.CurrentStatusCode));
10: rParam.Add("CurrentVersion", electronicApproval.CurrentVersion);
11:
12: rParam.Add("Language", SetNullAsValue(electronicApproval.Language, Session.LANGUAGE));
13:
14: electronicApproval.SetHistoryRequiredParameter(rParam);
15: }
이렇게 구현한 확장메서드를 상속받은 클래스에서는 다음과 같이 이용합니다.
SetApprovalRequiredParameter(rParam);
이와 같이 인터페이스의 메서드 시그니쳐를 확장메서드를 이용해 구현하여 사용하는 방법도 있습니다.


