2009-06-10 4 views
2

현재 프로젝트의 대규모 체크 아웃 응용 프로그램을 작성 중입니다. 이 체크 아웃은 사용자의 관리자 수준, 체크 아웃 방법 및 체크 아웃 할 항목 유형에 따라 많은 경우가 있으므로 프로세스가 컨텍스트 클래스 집합을 통해 .aspx 페이지에서 추상화됩니다.어떤 하위 클래스가 필요한지 결정하는 가장 좋은 방법

이 클래스들은 모두 하나의 클래스 인 CheckoutContext에서 하위 클래스로 분류되며 사용되는 클래스 유형은 열거 형을 통해 표시됩니다.

내가 사용하는 서브 클래스를 선택하는 데 사용할 수있는 형식 정의를 유사한 뭔가가 있나요, 아니면 단순히과 같이, 관련 클래스를 반환하는 방법이 있어야합니다

CheckoutContext chooseSubclass(CheckoutCase c) 
{ 
CheckoutContext output; 
switch (c): 
{ 
    case CheckoutCase.SingleItemNew: 
    output = new SingleItemNew; 
    break; 
    case . . . 
    return output; 
} 
}

+1

얼마나 역동적입니까? 즉, 새 하위 클래스를 얼마나 자주 추가합니까? 응용 프로그램을 다시 컴파일하지 않고도 구성해야합니까? 이 하위 클래스를 만드는 여러 개발자가 있습니까? 이러한 유형의 요구 사항을 여러 개 처리하는 경우보다 강력한 솔루션이 필요할 수 있습니다. 그렇지 않다면 스위치를 붙이십시오. – Josh

+0

체크 아웃 프로세스가 너무 복잡하여 섹션별로 처리 할 수 ​​없다는 점에서 사용할 수있는 필드를 처리하기 위해 페이지 당 약 15 개의 메소드가 필요합니다. 따라서 우리는 프로세스를 클래스로 분리합니다. 나중에 더 많은 기능이 구현 될 가능성이 매우 높기 때문에 체크 아웃 프로세스를 추가하기위한 노력이 거의 필요하지 않습니다. –

답변

1

If there are a large number of cases, I would create a Dictionary<CheckoutCase, Type>와의 세트로 하나 시간을 채울 모든 CheckoutCase 값 및 해당 CheckoutContext 유형 그런 다음 Activator.CreateInstance를 사용하여 거대한 switch 문 대신 적절한 유형을 반환 할 수 있습니다.

당신은 CheckoutContext의 유형이 될 것입니다 하나 개의 속성을 갖는 속성을 만들 수 있습니다
+0

나는 결국이 버전으로 갔다. 케이스는 읽기가 너무 어려워졌다. –

4

What you're implementing is a Factory Pattern . This is a standard practice, though it typically means writing a lot of repetitive code (much like your switch statement, which is often how they're implemented). You could do all sorts of fancy things like dynamic instantiation via reflection, but don't play with fire. Just stick with switch statement and you'll be fine.

0

You could implement this with a custom attribute and a factory method. Make all you Sub Classes implement a CustomAttribute say CheckOutCaseScenarioAttribute that takes the CheckOutCase Enum value.

Within your factory method, look for types that have this Enum Value set and create the object. This will avoid your switch case. This will work if you dont have any other initialization logic within your factory method.

0

This is called a Factory Design Pattern. I would create a static method that returns the needed class. A good practice here is to implement an Interface and return the interface.

interface ICheckoutItem 
{ 
    void CheckOut(); 
} 

Have your items implement the interface. Then in your factory method return the interface of each item.

ICheckoutItem chooseSubclass(CheckoutCase c) 
{ 
ICheckoutItem output; 
    switch (c): 
    { 
     case CheckoutCase.SingleItemNew: 
     output = new SingleItemNew; 
     break; 
     case . . . 
    return output; 
    } 
} 
+0

기본 클래스 대신 인터페이스를 반환 할 때 어떤 이점이 있습니까? 장점이 없으면이 대답은 현재 솔루션과 동일합니다. –

+0

나는 다른 누군가가 나보다 위에 현재 대답을 썼던 것에 따라 이것을 썼다. 사실 나는 심지어 그의 대답을 upvoted했다. 인터페이스는 더 나은데, 그 이유는 결국 같은 Base 클래스에서 상속받지는 않지만 여전히 "체크 아웃"해야 할 항목을 가질 수 있기 때문입니다.이 시점에서 메서드 및 논리가 특정 클래스에 종속되지 않으므로 최소 리팩토링이 필요합니다. –

0

:

public class CheckoutContextAttribute : Attribute 
{ 
    public Type CheckoutType{get;set;} 
} 

그런 다음 열거에 올바른 열거 형의 올바른 속성을 넣을 수 있습니다 :

public enum CheckoutCase 
{ 
    [CheckoutContext(CheckoutType=typeof(SingleItemNew)] 
    SingleItemNew, 
    ... 
    ... 
} 

그런 다음, 당신은 당신이 반사를 사용하는 올바른 컨텍스트 유형을 다시 보내 같은 것을 할 필요가있는 방법 :

public CheckoutContext GetContext(CheckoutCase c) 
{ 
    FieldInfo field = c.GetType().GetField(c.ToString()); 
    object[] attribs = field.GetCustomAttributes(typeof(CheckoutContextAttribute),false); 
    CheckountContext result = null; 
    if(attribs.Length > 0) 
    { 
     CheckoutContextAttribute attrib = attribs[0] as CheckoutContextAttribute; 
     Type type = attrib.CheckoutType; 
     result = Activator.CreateInstance(type) as CheckountContext; 
    } 

    return result; 
} 
을 0

트릭을해야합니다. 안전을 위해 몇 가지 null/오류 검사를 추가하십시오.

관련 문제