Esiste un numero minimo di argomenti richiesti per l'uso di un oggetto dati?

0

Dire che ho una classe di calcolatrice simile a questa:

using System;

public class CalCulator
{
    public int Square(int num)
    {
        return num*num;
    }

    public int Add(int num1, int num2 )
    {
        return num1 + num2;
    }

    public double Add(double num1, double num2 )
    {
        return num1 + num2;
    }

    public int Multiply(int num1, int num2 )
    {
        return num1 * num2;
    }

    public int Subtract(int num1, int num2 )
    {
        if ( num1 > num2 )
        {
            return num1 - num2;
        }

        return num2 - num1;
    }
}

Questo mostra come usare la classe Calculator dal programma Main C #.

public class Class1
{
    static void Main()
    {
        CalCulator sq = new CalCulator();
        Console.WriteLine( sq.Square(8).ToString());
        Console.WriteLine( sq.Add(8.3, 9.24).ToString());
        Console.WriteLine( sq.Multiply(5,8).ToString());
        Console.WriteLine( sq.Subtract(22, 42).ToString());
    }
}

Fonte (compresa la mancanza di formattazione): Una semplice classe di calcolatori di Mahesh Chand

Diciamo che tutti i metodi accettano due argomenti (mi rendo conto che questo non è vero nell'esempio che ho fornito poiché contiene un metodo chiamato: Square, che accetta un argomento).

Sarebbe "meglio" utilizzare un oggetto dati che raggruppa i due argomenti insieme? Credo che ciò aiuterebbe con la testabilità (inversione di controllo, iniezione di dipendenza, eccetera)?

Esiste un numero minimo di argomenti richiesti prima di utilizzare un oggetto dati per passarli a un metodo?

Aggiorna

La calcolatrice forse non è la migliore analogia per spiegare la mia domanda. Supponiamo che abbia una funzione che restituisca un elenco come segue:

public List<PercentageValues> CalculateTaxGroupedByPercentage()
{
}

public class PercentageValue()
{
    private int decimal _percentage;
    private readonly decimal _value;

    public PercentageValue(int percentage, decimal value)
    {
       _percentage = percentage;
       _value = value;
    }
}

Ad esempio, se una persona ha uno stipendio di £ 60.000, allora CalculateTaxGroupedByPercentage () restituirà il seguente elenco:

List<PercentageValue> list = new List<PercentageValue>();
list.Add(new PercentageValue(20,45000);
list.add(new PercentageValue(40,15000);

Due domande:

1) È un tipo di DTO / Valore valido? 2) Qual è la differenza tra un DTO e un tipo di valore? Pensavo che un DTO fosse per il trasferimento di dati su domini applicativi, ad es. un servizio web che restituisce una classe a un cliente. In tal caso questo non è un DTO.

    
posta w0051977 21.06.2017 - 23:52
fonte

6 risposte

2

Il primo commento da fare qui è che, quando si utilizza qualsiasi linguaggio .NET, è necessario fare attenzione sull'uso del termine tipo di valore . Le strutture di C # sono tipi di valore quando vengono passati per valore, non per riferimento. Il termine che ho comunemente visto usato per quello che stai chiedendo è "oggetti valore", ma anche quello può essere confuso come potrebbero essere le strutture.

Per sapere se il seguente codice è un "DTO" valido:

public class PercentageValue()
{
    private int decimal _percentage;
    private readonly decimal _value;

    public PercentageValue(int percentage, decimal value)
    {
        _percentage = percentage;
        _value = value;
    }
}

La risposta è "no" semplicemente perché quel codice non consente la lettura dei valori, quindi è piuttosto inutile. Risolto il problema e quindi sì, è valido semplicemente perché è un mezzo per trasferire dati tra i metodi:

public class PercentageValue()
{
    public int Percentage { get; }
    public decimal Value { get; }

    public PercentageValue(int percentage, decimal value)
    {
        Percentage = percentage;
        Value = value;
    }
}

Riguardo a " Qual è la differenza tra un DTO e un tipo di valore? ", la risposta è: semantica. In senso stretto, in C #, i tipi di valore sono le strutture e le enumerazioni e non sono correlati ai DTO. Ma nel modo in cui li stai usando nella tua domanda, sono la stessa cosa.

Nell'esempio della tua calcolatrice. Come altri hanno già detto, ha perfettamente senso avere due parametri, piuttosto che raggruppare i valori in un oggetto transitorio da passare come un parametro. Inoltre, poiché sono tutte funzioni pure, renderle statiche, piuttosto che creare inutilmente un oggetto solo per farvi riferimento.

Un'ultima cosa, a meno che non ci sia una buona ragione per cui non puoi farlo, usa VS2017 e C # 7 per evitare di dover creare il tuo "DTO" e solo restituire una tupla:

IEnumerable<(decimal percentage, decimal value)> CalculateTaxGroupedByPercentage()
{
    yield return (20,45000);
    yield return (40,15000);
}
    
risposta data 22.06.2017 - 10:43
fonte
8

Penso che stai chiedendo se dovessi cambiare questo

double Add(double lhs, double rhs) {
    return lhs + rhs;
}

a questo:

class AddParameters {
    public double LHS { get; set; }
    public double RHS { get; set; }
}

double Add(AddParameters params) {
    return params.LHS + params.RHS
}

La risposta è no, sarebbe assolutamente ridicolo. Beh, forse andrebbe bene in un linguaggio di programmazione funzionale, ma non c #.

Il luogo in cui si applicherebbe questo principio sarebbe con una serie di parametri correlati che sono ingombranti da aggirare, ad es. invece di

void AddUser(string firstName, string lastName, string street, string city, string state)

forse useresti qualcosa di simile

class UserDto
{
    string FirstName { get; set; }
    string LastName { get; set; }
    string Street { get; set; }
    string City { get; set; }
    string State { get; set; }
}

void AddUser(UserDto user)

Esiste un numero magico di parametri? No, è una sentenza. Passerai all'utilizzo di una sorta di oggetto DTO o parametro se diventa troppo doloroso per passare i dati separatamente, o se hai bisogno di persistere o trasmettere i parametri come gruppo (ad esempio passando l'utente a una funzione separata per stampare), oppure se hai diverse funzioni che richiedono tutti lo stesso gruppo di parametri.

    
risposta data 22.06.2017 - 02:23
fonte
7

Is there a minimum number of arguments required for a value type?

Penso che ci sia un modo migliore di considerare questo rispetto al conteggio dei parametri di un metodo come soglia di complessità, e va all'astrazione: al raggruppamento implicito di coppie (o triple o più) che i clienti gestiscono in il loro codice rispetto al raggruppamento esplicito che si manifesta come una singola entità programmatica per i client da gestire.

Quando un metodo ha molti parametri spesso molti dei parametri sono strettamente correlati: così strettamente correlati, infatti, che sono trattati come un gruppo dai clienti, in altre parole, abbiamo un concetto implicito. Pertanto, l'idea non è necessariamente quella di creare un oggetto dati che contiene tutti i parametri per il metodo, ma piuttosto identifica uno o più concetti impliciti nell'elenco dei parametri e riorganizza quelli insieme in astrazioni esplicite.

Ad esempio, foo ( int x, int y, int count ) - qui potremmo prendere le coordinate x e y e raggrupparle insieme, spostandole da un concetto implicito a un'astrazione esplicita. Questo senza necessariamente influenzare il parametro count , che rimane come è (vale a dire che non stiamo necessariamente creando un'astrazione per l'intero elenco di parametri nella sua interezza).

Un "punto" avente int x e int y è una migliore astrazione di due int per diversi motivi. Innanzitutto, il punto, una volta creato può essere trattato dal cliente come un'unica entità da utilizzare e da gestire e ragionare. Secondo, nella maggior parte delle lingue, avrà una sicurezza di tipo aggiuntiva. In terzo luogo, quando si chiama un metodo che prende più punti, sarà molto più difficile avere un errore di battitura come passare x1, y1, x1, y2 quando quest'ultimo era destinato a essere x2, y2. Inoltre, l'entità punto può fornire metodi di base (ad es. Serializzazione e deserializzazione) che rendono l'astrazione più strong.

Comune tra i motori di calcolo e la valutazione dell'espressione è un metodo per memorizzare più operandi, ad esempio utilizzando una pila di operandi. Usandolo come astrazione, puoi ridurre il numero di parametri, magari anche a zero se condividi lo stack nel costruttore. L'astrazione dello stack fornisce una singola entità che raggruppa più operandi. Possiamo persino eliminare i valori di ritorno, riportando il risultato in pila.

Naturalmente, in questo semplice esempio, i diversi tipi di calcolatrice possono essere gestiti avendo due stack diversi (uno stack int, un doppio stack) o un tag type e conversioni di tipo (ad esempio la promozione di int a double).

    
risposta data 22.06.2017 - 03:11
fonte
1

Is there a minimum number of arguments required for the use of a data object?

In realtà, non si tratta del numero di argomenti. Riguarda il modo in cui fanno apparire l'uso del codice.

Ho seguito questa domanda per un po 'e vedo delle buone risposte qui. Normalmente me ne andrei da solo ma non riesco a scuotere la sensazione che qui manchi un punto importante.

Console.WriteLine( sq.Add(8.3, 9.24).ToString());

Un problema con questo potrebbe non avere nulla a che fare con il fatto che ci sono solo 2 argomenti passati invece di dire 15. Potrebbe essere che qualunque cosa usi questo metodo di aggiunta deve SAPERE che ce ne sono due allo stesso tempo che ha per sapere che vuole aggiungere.

C'è un refactoring ben documentato che dovresti cercare qui. Si chiama Introduce oggetto parametro . La cosa principale che fa è farti apparire la riga precedente in questo modo:

Console.WriteLine( sq.Add(operands).ToString());

Il motivo per farlo non è perché è molto più facile gestire argomenti 1 vs 2. È che ora, proprio qui, non sappiamo se il numero di operandi sia 1, 2 o 42. Ciò significa che questa interfaccia è meno accoppiata a quei dettagli di implementazione e può variare in modo più indipendente. La riduzione dell'accoppiamento viene ingrandita se vi sono molti metodi che utilizzano gli stessi operandi. Non sappiamo nemmeno se operands sia un DTO, una tupla, una raccolta o anche un oggetto comportamentale che sta per aggiungere qualche lambda. Non vogliamo saperlo.

Alcune persone trovano effettivamente fastidiosa questa mancanza di conoscenza. Per loro questo potrebbe anche essere considerato più difficile da leggere. Quindi non fare questo pensiero in meno è sempre meglio per la lettura. No, si tratta di essere sicuri di essere flessibili e pronti ad accettare i cambiamenti.

Quando si tratta di leggibilità, un oggetto dati è difficilmente l'unica opzione. L'utilizzo di argomenti con nome può aiutare a ridurre il dolore di arity dal momento che non chiedi alle persone di ricordare l'ordine degli argomenti. In una lingua senza argomenti di nome è possibile utilizzare modelli di build come Josh Bloch Builder che li simula in modo efficace.

A volte gli argomenti sono raggruppati insieme che non vengono prima scoperti tutti allo stesso tempo. Questi possono essere separati da quando vengono appresi. Questa è una delle grandi cose a cui penso quando decido quali argomenti possono andare nel costruttore.

A volte non è leggibile, ma sei costretto ad affrontare argomenti che preferiresti non trattare poiché non hanno nulla a che fare con la tua responsabilità. In quei casi ciò di cui hai veramente bisogno è un riferimento a un oggetto comportamentale che già sa cosa deve sapere che puoi solo dire di fare cose.

E sì a volte un oggetto dati / parametro migliorerà la leggibilità. In realtà, si tratta solo di considerare la lista degli argomenti come qualcosa di più di un semplice posto per accumulare dipendenze. È bello se la pila può essere organizzata. Un oggetto dati è semplicemente uno dei tanti modi per organizzarlo.

La migliore organizzazione viene fornita con buone astrazioni. Sarebbe giustificabile mettere in discussione quanto sia leggibile Add(operands) ma Display(point) sembra molto naturale. Strutturalmente, non sono diversi. Ma l'astrazione è molto più stretta perché è molto facile immaginare esattamente cosa si nasconde sotto il nome point .

È quando non rispetti questo bisogno di non sorprendere le persone che diventano ossessionate dall'appiattimento di tutto. Guardare una tonnellata di argomenti è un dolore, ma è meglio allora dover indovinare cosa significa LHS .

In breve:

  1. Ben organizzato con buoni nomi e astrazioni coerenti, che sono meglio di
  2. Elenchi semplici e diretti di tutto, che sono meglio di
  3. Strutture disorganizzate, nomi misteriosi e astrazioni che perdono.

Molte persone preferiscono 2 proprio perché è difficile dire se si sta creando 1 o 3. Ecco perché abbiamo revisioni tra pari. Non provare 1 senza un amico.

    
risposta data 22.06.2017 - 21:28
fonte
0

Non ho mai sentito di alcuna regola, best practice o linea guida che dice che se hai più di X numero di parametri dovresti avvolgerli con una classe e passare l'oggetto classe come un singolo parametro. Direi che dipende dal tuo personale stile di programmazione e dal tuo istinto.

Detto questo, se sei (o lo farai) passando lo stesso insieme di parametri ad altri metodi / classi e raramente (se mai) usi gli attributi individuali da solo, allora dovrebbe alzare una bandiera che sarebbe Vale la pena seriamente pensare di metterti in classe. Ciò porterebbe a un codice più pulito e a un codice meglio gestibile.

Ad esempio, consideriamo una "persona" che ha un nome. Sono solo due valori di stringa, quindi basandoti su alcune regole che 5 o meno non dovrebbero essere una classe e dovrebbero essere passate ai parametri, hai un'app che ha molti metodi che si occupano della persona e di quei due attributi. Ora qualcuno ricorda che dovrebbe esserci un secondo nome. Ora devi visitare tutti quei posti per aggiungere il terzo parametro.

Ora qualcun altro ricorda che alcune persone vanno con il loro nome, altre con il loro secondo nome e altre con un soprannome. Quindi ora stai aggiungendo più parametri in tutti questi luoghi, oltre a un valore che tiene traccia se la persona vuole essere chiamata dal loro primo, medio o soprannome .... e ora in tutto il codice stai trovando tutti i luoghi in cui il alla persona viene presentato un saluto di benvenuto e l'inserimento di quella logica.

Speriamo che prima di andare troppo in là lungo quel percorso ti facciano il backup e dica che "persona" dovrebbe essere una classe. Più velocemente decidi di farlo, meno mal di testa provi.

Inoltre, come mostra il tuo esempio, quando vuoi usare classi come le raccolte predefinite di lingua (Elenco, ecc.) per gestire il tuo "gruppo" di attributi, questo è un segno sicuro che devi avvolgere quegli attributi con una classe. E non sarà troppo lontano lungo la strada che è necessario mantenere i propri attributi nello spazio di archiviazione, serializzare / deserializzare per l'integrazione con altri microservizi, ecc.

    
risposta data 22.06.2017 - 22:15
fonte
-5

Il valore è un valore singolo. Puoi chiamare una funzione e dire che il suo risultato è un singolo valore come:

function example($a, $b){
  return $a + $b; 
}
Value X = example(a, b); 
    
risposta data 22.06.2017 - 00:03
fonte

Leggi altre domande sui tag