2009-06-10 5 views
2

Je travaille sur une application de paiement à grande échelle pour un projet en cours. Cette extraction a de nombreux cas en fonction du niveau d'administration de l'utilisateur, comment ils sont arrivés à la caisse, et quel type d'article ils extraient, et donc le processus est extrait des pages .aspx via un ensemble de classes de contexte.Meilleure façon de décider quelle sous-classe est nécessaire

Ces classes sont toutes sous-classes à partir d'une seule classe, CheckoutContext, et le type de classe à utiliser est noté via une énumération.

Y at-il quelque chose de similaire à typedef je peux utiliser pour choisir la sous-classe à utiliser, ou devrais-je avoir simplement une méthode qui retourne la classe concernée, comme suit:

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

+1

De quelle dynamique avez-vous besoin? Je veux dire, à quelle fréquence ajoutez-vous de nouvelles sous-classes, et doivent-elles être configurées sans recompiler votre application? Avez-vous plusieurs développeurs qui créent ces sous-classes? Si vous traitez plusieurs de ces types d'exigences, vous aurez peut-être besoin d'une solution plus robuste. Si non, alors restez avec l'interrupteur. – Josh

+0

Tout le problème est que le processus de commande est trop complexe pour traiter un cas section par section, nous aurions besoin d'environ 15 méthodes par page pour gérer les champs disponibles. Ainsi, nous séparons le processus en classes. Il y a une très bonne possibilité que d'autres seront faites plus tard, donc je veux une solution qui nécessite peu d'effort supplémentaire pour ajouter un processus de paiement. –

Répondre

1

If there are a large number of cases, I would create a Dictionary<CheckoutCase, Type> et le remplir une fois avec l'ensemble des toutes les valeurs CheckoutCase et les Types CheckoutContext correspondants. Vous pouvez ensuite utiliser Activator.CreateInstance pour renvoyer le type approprié au lieu d'une instruction gigantesque.

+0

Je suis finalement allé avec cette version, l'affaire devenait trop difficile à lire! –

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

Quel avantage y a-t-il à retourner une interface au lieu d'une classe de base? S'il n'y a pas d'avantage alors cette réponse est identique à la solution actuelle. –

+0

j'ai écrit ceci comme quelqu'un d'autre a écrit la réponse actuelle au-dessus de moi ... en fait j'ai même upvoted sa réponse. Les interfaces sont meilleures car vous pouvez avoir des objets qui n'hériteront pas de la même classe de base mais qui doivent être "extraits", à ce stade vous aurez besoin d'un refactoring minimum car vos méthodes et votre logique ne dépendront pas d'une classe spécifique. –

0

Vous pouvez créer un attribut qui a une propriété qui serait le type de CheckoutContext:

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

Ensuite, sur votre ENUM, vous pouvez mettre l'attribut correct sur le type ENUM correct:

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

Ensuite, dans cette méthode où vous devez renvoyer le bon type de contexte que vous utilisez la réflexion et faire quelque chose comme ceci:

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; 
} 

Cela devrait faire l'affaire. Ajoutez juste une vérification de null/error pour être sûr.

Questions connexes