Riduce il numero di istruzioni if attraverso il modello di progettazione

3

Ho avuto un ciclo attraverso l'oggetto Process , ciascuna istanza process può essere di un tipo diverso, derivata da Process classe base (ad esempio Process1 , Process2 , ...). Ogni tipo derivato di Process ha proprietà diverse. Ad esempio: alcuni Process es sono indicizzabili, questo è segnalato da IsIndexable flag. Quando un Process è indicizzabile ha alcune proprietà aggiuntive (ad esempio: AccessDate ) che il processo non indicizzabile non ha. Ora devo fare un ciclo su ogni processo in request.Process (ricorda che il% indicizzabileProcess es sono diversi dagli altri)

foreach (Process process in request.Processes)
{
     if(process.getType().Name.Equals("Process1")) // indexable process
     {
         ((Process1)process).Name = "aName";
         ((Process1)process).AccessDate = DateTime.Now;
     }
     else if(process.getType().Name.Equals("Process2")) // non indexable process
     {
         ((Process2)process).Name = "anotherNane";
         //compile error - AccessDate don't exist for type Process2
         //((Process2)process).AccessDate = DateTime.Now;          
     }
}

Poiché odio quella cascata se ho riscritto usando l'interfaccia:

IProcessable processableImpl = // some Unity stuff based on request type
foreach (Process process in request.Processes)
{
     processableImpl.fillTheRightProperties(process);
}

processableImpl è iniettato in un modo diverso basato su request.Type . A questo punto il metodo fillTherRightProperties farà il lavoro per me sull'attuale process .

public interface IProcessable
{
    void fillTheRightProperties(Process process);
}

public class IndexableProcess : IProcessable 
{
    void fillTheRightProperties(Process process){
        Process1 process1 = process as Process1;

        if(process1==null) throw MyException("Process1 expected");

        process1.Name = "aName";
        process1.AccessDate = DateTime.Now;
    }
}

public class NonIndexableProcess : IProcessable 
{
    void fillTheRightProperties(Process process){
        Process2 process2 = process as Process2;

        if(process2==null) throw MyException("Process2 expected");

        process2.Name = "aName";
    }
}

Questo è più bello di un if a cascata, ma non mi sento ancora così bello come potrebbe essere. Sento una violazione della responsabilità, poiché la classe concreta modifica process proprietà altrove, e ho paura di leggere questo codice una settimana dopo.

    
posta BAD_SEED 18.06.2014 - 16:06
fonte

2 risposte

4

Di seguito è riportato un esempio che utilizza un'interfaccia e due implementazioni in un'applicazione console:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var processes = new List<IProcessable>();
            processes.Add(new Process1());
            processes.Add(new Process2());

            foreach (IProcessable item in processes)
            {
                item.FillTheRightProperties();
            }

            Console.WriteLine();
            Console.WriteLine("Press Enter/Return to exit...");
            Console.ReadLine();
        }
    }

    interface IProcessable
    {
        void FillTheRightProperties();
    }

    class Process1 : IProcessable
    {
        public string Name { get; set; }
        public DateTime AccessDate { get; set; }

        public void FillTheRightProperties()
        {
            this.Name = "aName";
            this.AccessDate = DateTime.Now;

            Console.WriteLine("Properties filled: {0}, {1}", this.Name, this.AccessDate);
        }
    }

    class Process2 : IProcessable
    {
        public string Name { get; set; }

        public void FillTheRightProperties()
        {
            this.Name = "aName";

            Console.WriteLine("Properties filled: {0}", this.Name);
        }
    }
}

La linea chiave si trova in foreach in cui utilizziamo l'interfaccia anziché eseguire il cast in una classe concreta.

Per mappare questo al tuo esempio request.Processes sarebbe un List<IProcessItem> che significa che possiamo garantire che il metodo DoSomething() esista e che non sia necessario eseguire il cast in una classe concreta.

È possibile utilizzare anche la classe base, ma lo scopo è quello di tenere solo il codice comune.

    
risposta data 18.06.2014 - 16:34
fonte
0

Usa un hash che contiene come chiave il nome del processo e come valore l'oggetto che contiene il processo. In questo modo ottieni solo una riga di codice:

Nota: quanto segue è in perl dato che non conosco C #, ma la logica è la stessa

$hashContainingProcesses{processName}.doSomething();

A seconda di come C # gestirà questo probabilmente vorrai controllare prima se la chiave esiste .

    
risposta data 18.06.2014 - 16:13
fonte

Leggi altre domande sui tag