Passando due tipi diversi lungo una catena di chiamate a causa di un sovraccarico più in basso

1

Mi sono un po 'confuso. Ho il codice proveniente da Main, tramite myMethod e giù su OtherMethod. Uno dei parametri può essere un int o una stringa, che influenza OtherMethod ma nessuno dei metodi intermedi.

public static void Main()
{
    myMethod(number: 10);
    myMethod(letters: "ten");
}

public static void myMethod(int number = 0, string letters = null)
{
    //long entirely shared code with calls to:
    OtherMethod(number,letters);
}

public static void OtherMethod(int number = 1, string letters = null)
{
    //Lots of shared code, embedded multiple times within this code is essentially:
    if (letters != null)
    {
        Console.WriteLine("letters!");
    }
    else
    {
        Console.WriteLine("numbers!");
    }
}

OtherMethod si preoccupa di quando sto passando a int o string , ma nessuno dei metodi intervistati si preoccupa. Troverò anche la divisione di OtherMethod senza riutilizzo del codice non necessario molto difficile.

La soluzione che ho fornito funziona, ma probabilmente è un anti-pattern. Perché, ad esempio, una chiamata a myMethod(10,"ten") rigirerebbe silenziosamente 10 nel cestino.

La modifica in private mymethod(int number = 0, string = null) chiamata da public (int number) e public (string letter) per ogni livello sarebbe una pessima idea?

Ho pensato di passare invece una classe con int e string e le istruzioni da usare direttamente dall'alto in basso. Sospetto che questa sia la soluzione. Ma sembra OTT quanto OO.

Il mio vero caso d'uso è che sto generando dati casualmente nella parte inferiore di questa catena e posso fornire un seed (int) o un cheat e fornire i dati da generare (string). Mi viene in mente che quello che sto facendo potrebbe essere una scusa per l'iniezione della dipendenza procedurale,

    
posta Nathan Cooper 01.07.2014 - 17:36
fonte

3 risposte

4

Sei sulla strada giusta pensando di dover iniettare una classe piuttosto che i parametri int e string , ma in realtà vuoi iniettare una delle classi due che implementano un'interfaccia comune: uno con una specializzazione int e uno con una specializzazione string .

Per evitare la duplicazione in OtherMethod , è possibile creare quel codice comune che richiama le funzioni di supporto specifiche dell'implementazione secondo necessità. In altre parole, ovunque tu abbia if (letters != null) , metti una chiamata a HelperMethod() .

Non conosco C #, quindi considera questo pseudocodice, ma sarebbe simile a questo:

public static void Main()
{
    myMethod(new IntGenerator(10));
    myMethod(new StringGenerator("ten"));
}

public static void myMethod(Generator gen)
{
    //long entirely shared code with calls to:
    gen.OtherMethod();
}

abstract class Generator {
    abstract void HelperMethod();

    public void OtherMethod()
    {
        //Lots of shared code, embedded multiple times within this code is:
        HelperMethod();
    }
}

class IntGenerator extends Generator
{
    IntGenerator(int value) {}

    void HelperMethod() 
    {
        Console.WriteLine("numbers!");
    }
}

class StringGenerator extends Generator
{
    StringGenerator(string value) {}

    void HelperMethod() 
    {
        Console.WriteLine("letters!");
    }
}

Sì, questo crea molte più funzioni, ma se lo dividi correttamente, sarà molto più facile da mantenere.

    
risposta data 01.07.2014 - 19:06
fonte
1

Potresti utilizzare Core.Choice o un'unione delimitata a tuo piacimento.

Se devi passare uno o l'altro valore, non permettere di passare entrambi.

    
risposta data 01.07.2014 - 19:33
fonte
1

Vorrei andare molto più in profondità di Karl e convertire l'intero myMethod e OtherMethod in una classe. Quindi puoi utilizzare l'ereditarietà e il metodo astratto per differenziare i casi.

public abstract class Generator
{
    public void Invoke()
    {
        //long entirely shared code with calls to:
        OtherMethod();
    }

    protected abstract void OtherMethod();
}

public class IntGenerator : Generator
{
    private int _number;
    public IntGenerator(int number)
    {
        _number = number;
    }

    protected override void OtherMethod()
    {
        Console.WriteLine("numbers!");
    }
}

public class StringGenerator : Generator
{
    private string _letters;
    public StringGenerator(string letters)
    {
        _letters = letters;
    }

    protected override void OtherMethod()
    {
        Console.WriteLine("letters!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        new IntGenerator(10).Invoke();
        new StringGenerator("ten").Invoke();
    }
}

Il vantaggio principale è che nel tuo codice puoi semplicemente utilizzare Generator e scambiarlo quando usi Int o String senza dover modificare il codice.

    
risposta data 01.07.2014 - 20:51
fonte

Leggi altre domande sui tag