Alternative per digitare casting nel tuo dominio

4

Nel mio dominio ho un'entità Activity che ha un elenco di ITask s. Ogni implementazione di questa attività ha le sue proprietà oltre all'implementazione di ITask stessa. Ora ogni operazione dell'entità Activity (ad esempio Execute() ) deve solo scorrere su questo elenco e chiamare un metodo ITask (ad esempio ExecuteTask() ).

Dove ho problemi è quando è necessario aggiornare le proprietà di attività specifiche, come nella configurazione dell'attività (non come parte del metodo di esecuzione). Come ottengo un'istanza di tale attività? Le opzioni che vedo sono:

  • Ottieni l'attività per ID e lancia l'attività di cui ho bisogno. Questo o cospargerà il mio codice con:
    • Tasks.OfType<SpecificTask>().Single(t => t.Id == taskId)
    • o Tasks.Single(t => t.Id == taskId) as SpecificTask
  • Rendi ogni attività univoca nell'intero sistema (rendi ogni attività un'entità) e crea un nuovo repository per ogni implementazione ITask

Non mi piace nessuna delle due opzioni, la prima perché non mi piace il casting: sto usando NHibernate e sono sicuro che tornerà e morderò quando comincerò a usare Lazy Loading (attualmente NHibernate usa i proxy per implementare questo). Non mi piace la seconda opzione perché ci sono / ci saranno dozzine di diversi tipi di compiti. Il che significherebbe che dovrei creare tanti repository.

Mi manca una terza opzione qui? O nessuna delle mie obiezioni alle due opzioni non è giustificata? Come hai risolto questo problema in passato?

    
posta dvdvorle 23.10.2012 - 11:58
fonte

2 risposte

2

È vero che il cast è cattivo quando introduce l'accoppiamento. Ma questo non significa che sia sempre male. Non c'è molto sbagliato con

ITask task = Tasks.Single(t => t.Id == taskId);
IArduousTask arduous = task as IArduousTask;

if (arduous != null)
{
    arduous.HaveLunchBreak();
}

task.DoTask();

In questo modo, non siamo legati a un'implementazione di ITask o IArduousTask. E qualsiasi attività può implementare IArduousTask (con una diversa implementazione di HaveLunchBreak (), se si sceglie) e HaveLunchBreak verrà chiamato automaticamente. Ma le attività che non implementano IArduousTask non si interromperanno.

Tuttavia, nel tuo caso, dovresti probabilmente anche riconsiderare se i tuoi oggetti Task dovrebbero essere mutabili. Potrebbe essere meglio fare questo:

ITask updated = task.GetUpdated(someData);
activity.UpdateTask(updated);

Dove GetUpdated è un nuovo metodo su ITask e activity.UpdateTask corrisponde su updated.ID e sostituisce l'intero oggetto nella matrice. Ciò lascia l'implementazione di GetUpdated al tipo di attività stesso.

someData può essere tutti i dati che potrebbero essere richiesti per eseguire un aggiornamento di qualsiasi tipo di attività, oppure potrebbe essere un dizionario (o oggetto dinamico) contenente dati da un'interfaccia utente specifica dell'attività, passati in un compito specifico.

    
risposta data 23.10.2012 - 14:21
fonte
1

L'attività non dovrebbe conoscere la proprietà speciale.

Questa conoscenza appartiene a un metodo virtuale nella classe di attività come questa:

public class MyTask
{
    public virtual void ExecuteTask()
    {
        // ....
    }
}

public class MyTaskWithSpecialProperty : MyTask
{
    public int MySpecialProperty {get;set}
    public override void ExecuteTask()
    {
        CalculateSpecialProperty();
        base.ExecuteTask();
    }
    private void CalculateSpecialProperty()
    {
            MySpecialProperty++;
    }
}

L'attività non ha bisogno di sapere su MySpecialProperty quando si esegue

public class Activity 
{
    public void ExecuteTasks()
    {
        foreach(var task in this.Tasks)
            task.ExecuteTask();
    }
}
    
risposta data 23.10.2012 - 14:46
fonte

Leggi altre domande sui tag