Quando dovrei usare una classe di 2 proprietà su una struttura pre-costruita come KeyValuePair?


31

Quando dovresti inserire il tipo di dati Key / Value nella sua classe invece di utilizzare una struttura generica preconfigurata, come ad KeyValuePairo a Tuple?

Ad esempio, la maggior parte dei ComboBox che creo contengono un DisplayName e un valore. Questo è il tipo di dati che sto cercando di decidere quando inserire una nuova classe e quando usare semplicemente un KeyValuePair.

Attualmente sto lavorando a qualcosa che utilizza iCalendare alla fine i dati dell'utente selezionato vengono combinati in un key1=value1;key2=value2;tipo di stringa. Ho iniziato inserendo i dati in a KeyValuePair<string,string>, ma ora mi chiedo se quella dovrebbe essere la propria classe.

Nel complesso, sono interessato a scoprire quali linee guida vengono utilizzate quando si decide di utilizzare una struttura / classe esistente come un oggetto KeyValuePairover 2-property e in che tipo di situazioni si useranno l'una sull'altra.


3
Quale lingua? In Python non abbiamo questo dilemma, perché abbiamo il tupletipo.
S.Lott

3
@ S.Lott: .NET BCL ha tuple dalla v 4.0.
Oded,


1
@Oded In questo caso, sto costruendo qualcosa con iCalendare volevo oggetti per BYDAYe BYSETPOS. Appaiono nei ComboBox, ma i dati effettivi vengono combinati nella stringa della regola ricorrente, che è un key=value;tipo di stringa
Rachel,

4
@ Rachel: aggiorna la domanda per essere più specifici. Un sacco di commenti non sono il modo migliore per chiarire le cose.
S.Lott

Risposte:


26

In genere utilizzerei un oggetto anziché un KeyValuePair o Tuple nella maggior parte dei casi. In primo luogo, quando vieni 6 mesi dopo per apportare modifiche, è molto più facile capire quale fosse il tuo intento prima piuttosto che chiederti cosa Tuple tsia e perché abbia quei valori divertenti. In secondo luogo, man mano che le cose crescono e cambiano, puoi facilmente dare il comportamento dei tuoi oggetti di trasferimento dati semplice, se necessario. Devi avere due formati di nome? Semplice, basta aggiungere gli opportuni sovraccarichi ToString (). Ti serve per implementare qualche interfaccia? Nessun problema. Infine, la creazione di un oggetto semplice è quasi zero, soprattutto con proprietà automatiche e completamento del codice.

Bonus Protip: se vuoi impedire a questi oggetti di inquinare il tuo spazio dei nomi, rendere le classi private all'interno delle classi è un ottimo modo per tenere le cose sotto controllo e prevenire strane dipendenze.


1
DTO = Oggetti trasferimento dati ? - Odio i TLA ;-)
Ben

3
@Ben - TFTFY. . .
Wyatt Barnett,

7

La regola per definire una nuova classe è semplice: è riassunta da "Occam's Razor".

http://c2.com/cgi/wiki?OccamsRazor

Non introdurre nuove classi senza una buona ragione. Oppure utilizza le classi predefinite il più possibile. O inventa il meno possibile. Comunque ti senti a tuo agio a scrivere meno codice.

Non è possibile utilizzare una classe precostruita se è necessario assegnare una responsabilità univoca all'oggetto e tale responsabilità non è definita nella classe precostruita. Spesso questo è un metodo unico.

A tupleo KeyValuePairè preferito.

Fino a.

Hai bisogno di alcune funzionalità che non fanno parte di A tupleo KeyValuePair. Quindi devi definire la tua classe.


3
" Non progettare mai ciò che puoi rubare " Riguarda il mio modo preferito di esprimerlo.
SingleNegationElimination,

1
Considerereste la semantica come "funzionalità che non fa parte di un tupleo KeyValuePair"? KeyValuePair ha almeno una forma limitata di semantica, ma le tuple raramente fanno (potrebbe essere possibile, a seconda del contesto). L'introduzione di una nuova classe dovrebbe darti una semantica chiara, ovviamente.
Mal Ross,

+1 Non rattoppare un tutto in una barca con del nastro adesivo se può adattarsi a una spina.
Evan Plaice,

4
Penso che questo sia un uso fuori luogo del rasoio di Occam. In secondo luogo, è importante sapere quali informazioni sono contenute in una variabile. -1.
Bent

4

Se scrivi la tua classe, hai un posto chiaro dove mettere la documentazione su quali sono i due valori. Soprattutto perché due stringhe non sono una definizione molto chiara. Tuttavia potresti scrivere qualcosa del genere

 public class MyPair : Tuple<string, string>

Mi piace perché MyPairdefinisce quali sono i valori di Tuple e a cosa servono.
Estratto

2
Ma poi le tue proprietà verrebbero chiamate Item1e Item2! Definire l'intera classe non è altrettanto semplice? public class SideStrings { public string Left { get; set; } public string Right { get; set; } }
configuratore

@configurator Stavo scrivendo una risposta a questo e ho notato che Tuple è letta solo quindi sono d'accordo sul fatto che penso metta tutto in discussione. Anche se potresti avvolgere la tupla per nominare i valori come preferisci.
Firma il

2
@Sign: Ma qual è il punto? Creare la tua classe è meno lavoro che avvolgere una tupla.
configuratore

2
@configurator ottieni alcune cose di uguaglianza e confronto che funzionano meglio di un oggetto personalizzato, ma se è necessaria l'impostazione, la tupla è sicuramente la strada sbagliata da percorrere.
Firma il

4

S.Lott ha scritto

Non introdurre nuove classi senza una buona ragione. Oppure utilizza le classi predefinite il più possibile. Inventa il meno possibile.

Non è possibile utilizzare una classe precostruita se è necessario assegnare una responsabilità univoca all'oggetto che non è definito nella classe precostruita.

Lasciami dire perché ho un problema serio con questo. Da

KeyValuePair [stringa, stringa]

sembra essere a posto .... KeyValue [stringa, KeyValue [stringa, KeyValuePair [stringa, stringa]]] va bene? Non so che cosa dirà S. Lott a questo, ma il mio capo pensa è a posto.

Non oso dissentire. Ed ecco perché: riduce la leggibilità del codice che seguirà. La funzione che riempirà una tale struttura di dati sarà molto più complessa e soggetta a errori (err. Eccezione) (immagina almeno anche qualche logica aziendale). Non ho discusso troppo con il mio capo, ma lo dirò qui: la leggibilità supera i piccoli risparmi di spazio (che era il suo argomento). Quindi non sarebbe un oggetto di classe in cui ci sono alcuni campi; ma alcuni rimangono vuoti a volte meglio?

PS Sono un Ultra_Noob, quindi per favore dimmi se sbaglio.


2
Penso che KeyValuePair<string,string>vada bene, supponendo che le cose inserite siano davvero chiavi e valori. In questo caso, il riutilizzo di una classe esistente è una vittoria, poiché si salva la scrittura del codice e si ottiene l' interoperabilità. OTOH, usando qualcosa di complicato come il KeyValuePair<string,KeyValuePair<string,string>>più delle volte semplicemente troppo complicato per essere pratico. A volte può essere giusto - quando non hai bisogno di funzionalità aggiuntive, quando il significato è ovvio e quando funziona bene con altre classi. YMMV, questo sta solo ponderando i pro e i contras.
maaartinus,

Se stai usando C #, ecco le prestazioni di un Tuple vs KeyValuePair . Qualcosa che potresti voler condividere con il tuo capo?
Ben

3

Quando diciamo coppia chiave / valore , di solito penso a tabelle hash , a array associativi o semplicemente a un oggetto KeyValuePair . Li uso tutti e non c'è alcuna differenza in quando uso quale.

Penso che la cosa più importante in un elenco di coppie chiave / valore sia che, le chiavi dovrebbero essere uniche (dal momento che è una chiave dopo tutto), e tutte le strutture di cui sopra mi forniscono davvero quella funzionalità.

A parte questo, voglio cercare per chiavi o fare azioni in stile elenco (array) come push e pop.

Quindi, la mia risposta è NO , e non creo oggetti in modo esplicito per coppie chiave / valore, dal momento che molte strutture integrate lo fanno già per me.


3

Il capitolo sei di Clean Code ha una buona descrizione di quando usare una struttura di dati rispetto a una classe. In breve, si utilizza una struttura di dati quando si prevede principalmente l'aggiunta di nuove funzioni per operare su tali dati. Utilizzi una classe quando prevedi principalmente di aggiungere nuovi tipi di dati su cui operare con funzioni esistenti. ComboBox è un esempio di quest'ultimo. Hai un set di funzioni (l'implementazione di ComboBox) che operano su molti tipi di dati diversi (diversi tipi di dati per diversi widget).


2

Forse sarei d'accordo con Wilding qui , ma poi sono un po 'un po' noob anche in questo genere di cose.

Vorrei suggerire che i tipi predefiniti sono spesso oggetti meccanismo . KeyValuePair, ad esempio, fa parte del meccanismo di un dizionario e delle tabelle hash, contribuendo a garantire chiavi univoche e hanno proprietà che hanno nomi significativi nel contesto del meccanismo stesso.

D'altro canto, l'utilizzo di oggetti dati personalizzati offre una migliore rappresentazione dei dati e offre numerosi vantaggi, tra cui la leggibilità e l'estensibilità. Non c'è nulla che impedisca di riutilizzare il codice esistente negli oggetti personalizzati come suggerito da Sign , ma proverei a nascondere la classe di wrapping, evitando perdite di astrazione , in modo da poter modificare l'implementazione sottostante in un secondo momento senza influire sul resto del codice .

Quindi la vera domanda: rappresenti i dati o li stai usando in un meccanismo? (e non consiglierei di mescolare questi concetti insieme).

Nella mia esperienza non c'è niente di peggio che vedere una Tupla [stringa, stringa] passare in un metodo e non avere un modo immediato di sapere cosa dovrebbero essere Item1 e Item2. Meglio usare Tuple all'interno di metodi o solo come membri privati ​​di una classe.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.