2010-08-13 3 views
3

La classe de base est Tâche. Il existe plusieurs classes dérivées telles que PhoneCall, Fax, Email .... Le framework est .NET 3.5 et la langue est C#convertir le type de base en type dérivé

Dans notre application, nous voulons créer des tâches automatiques basées sur certaines règles pour un client . Par exemple. Si le client a été enregistré pendant 30 jours, une tâche sera créée par le moteur de règles.

Le propriétaire de la tâche devrait alors être capable de convertir cette tâche en un appel téléphonique, fax ..... basé sur le scénario. En outre, une autre exigence sera de convertir un appel téléphonique en fax ou e-mail ou vice versa.

1) Devrait-il y avoir une classe convertie qui devrait faciliter cette conversion ou chaque objet métier devrait autoriser les méthodes à effectuer la conversion?

2) S'il y a des modèles de conception ou des conseils que quelqu'un peut fournir, ce sera génial.

Pratik

Répondre

4

L'héritage est pas nécessairement la meilleure façon de modéliser des problèmes où les instances de types peuvent changer au fil du temps.

Vous pouvez utiliser la composition à la place. Quelque chose comme:

class Task 
{ 
    private TaskDetail m_Detail; 

    public TaskDetail Detail { get { return m_Detail; } } 
} 

abstract class TaskDetail { ... } 

class PhoneCallDetail : TaskDetail { ... } 
class FaxDetail : TaskDetail { ... } 
class EmailDetail : TaskDetail { ... } 

Les tâches ne changeraient pas lorsque les détails de leurs tâches passeraient d'un type à un autre. Vous devrez également implémenter un code d'utilitaire pour convertir entre les différents types de tâches, le cas échéant.

Donc exemple d'utilisation pourrait ressembler à:

Task theTask = new Task(...); 
theTask.ConvertToEmail(); // internally establishes this as an email task 

EmailDetail detail = (EmailDetail)theTask.Detail; 
detail.EmailAddress = "[email protected]"; 

theTask.ConvertToFax(); // may transfer or lose some detail... 
FaxDetail faxDetail = (FaxDetail)theTask.Detail; 
faxDetail.FaxDate = DateTime.Now; 

// and so on. 

Le principal inconvénient de cette approche est ci-dessus que les consommateurs de la classe Task doivent utiliser des contrôles d'exécution pour déterminer le type de détail associé à la tâche avant de faire fonctionner sur elle ; qui a également nécessite alors coulée de la propriété détail partout:

Task someTask = ...; 
if(someTask.Detail is EmailDetail) 
{ 
    EmailDetail detail = (EmailDetail)someTask.Detail; 
    /* operate on email detail ... */ 
} 
else if(someTask.Detail is FaxDetail) 
{ 
    FaxDetail detail = (FaxDetail)someTask.Detail; 
    /* operate on fax detail ... */ 
} 

Comme le nombre de différents sous-types se développe, cette approche devient plus difficile de maintenir et d'évoluer. Si le nombre de sous-types est faible et susceptible d'être stable au fil du temps, il peut s'agir d'un choix raisonnable. En général, il est difficile de modéliser des situations comme celles-ci - et vous devez souvent faire des compromis en fonction du fournisseur de persistance utilisé, du nombre de types de détails et des cas d'utilisation impliquant des conversions d'un détail tapez à un autre.

Une autre approche de conception souvent utilisée dans de tels cas est Key-Value-Coding. Cette approche utilise un dictionnaire de clés/valeurs pour modéliser les différents éléments de données de différents types de détails. Cela permet aux détails d'être très flexibles, au prix de moins de sécurité au moment de la compilation. J'essaie d'éviter cette approche lorsque cela est possible, mais parfois, elle modélise mieux certains domaines de problèmes.

Il est en fait possible de combiner le codage de valeurs-clés avec une approche plus fortement typée.Cela permet à des détails d'exposer leurs propriétés (généralement à des fins de lecture seule) sans nécessiter l'appelant d'effectuer des contrôles d'exécution ou lance:

abstract class TaskDetail 
{ 
    public abstract object this[string key] { get; } 
} 

public class FaxDetail : TaskDetail 
{ 
    public string FaxNumber { get; set; } 
    public DateTime DateSent { get; set; } 

    public override object this[string key] 
    { 
     get 
     { 
      switch(key) 
      { 
       case "FaxNumber": return FaxNumber; 
       case "DateSent": return DateSent; 
       default:   return null; 
      } 
     } 
    } 
} 

public class EmailDetail : TaskDetail 
{ 
    public string EmailAddress { get; set; } 
    public DateTime DateSent { get; set; } 

    public override object this[string key] 
    { 
     get 
     { 
      switch(key) 
      { 
       case "EmailAddress": return EmailAddress; 
       case "DateSent":  return DateSent; 
       default:    return null; 
      } 
     } 
    } 
} 

// now we can operate against TaskDetails using a KVC approach: 
Task someTask; 
object dateSent = someTask.Detail["DateSent"]; // both fax/email have a DateSent 
if(dateSent != null) 
    // ... 
0

1) pour créer des tâches que vous pouvez utiliser la méthode de l'usine

2) Je ne pense pas que ce serait une bonne idée que le propriétaire doive convertir la tâche en sous-classes. peut-être que la stratégie ou les pétauges d'État aideraient là.

0

Dans votre situation particulière, les types ne sont pas la solution, car vous n'avez pas défini le comportement d'un appel téléphonique, d'un fax ou d'un e-mail au-delà de celui de la tâche. Si la seule chose que vous ferez est de stocker un numéro de téléphone dans un objet PhoneCall, vous avez déjà rompu l'encapsulation. La propriété PhoneNumber doit figurer sur l'objet Customer, tout comme l'adresse e-mail, l'adresse postale, le numéro de fax, etc.

Vous pouvez heureusement utiliser un enum TaskType comme propriété de la tâche jusqu'au point que la tâche change son comportement en fonction du type de tâche en cours. C'est le point que vous devrez vous soucier d'utiliser la conversion de type comme décrit par LBushkin.

Je peux vous voir dans une situation où vous utilisez une logique de présentation différente pour chaque tâche. Dans ce cas, vous utiliserez le motif Décorateur.

Questions connexes