È meglio avere funzioni separate o aggiungere più argomenti a una funzione? [chiuso]

5

Qual è lo stile migliore da seguire per cambiare la tensione su un alimentatore a 4 canali:

setChannelOneVoltage(voltage)
setChannelTwoVoltage(voltage)
setChannelThreeVoltage(voltage)
setChannelFourVoltage(voltage)

o

setVoltage(channel,voltage)
    
posta user124757 30.09.2014 - 10:15
fonte

9 risposte

12

Raccomanderò sicuramente la seconda variante.

  1. È più flessibile. Cosa succede se si adotta il codice per un altro dispositivo che non ha solo 4 ma 8, 16, 32 o anche più canali? Dovresti aggiungere sempre più metodi e il tuo codice diventerebbe sempre più complicato. Il codice non può essere condiviso tra i dispositivi, perché si finirebbe con metodi non validi. Ma quando il tuo codice lascia aperto il numero di canali, puoi utilizzare lo stesso codice per qualsiasi dispositivo.
  2. Quando è necessario impostare la tensione su più canali contemporaneamente (o tutti sullo stesso valore o su valori diversi letti da una struttura dati), è possibile farlo con un semplice ciclo. La prima versione richiederebbe di chiamare ogni singolo metodo separatamente.

A proposito, per una migliore leggibilità del codice, puoi sostituire i numeri di canale per costanti quando vuoi. Questo codice potrebbe essere ambiguo:

setVoltage(2, 4);  // Does this set channel 2 to 4V or channel 4 to 2V?

Ma questo è molto più leggibile:

setVoltage(CHANNEL_2, 4); // OK, channel 2 is now 4V, but what does channel 2 actually do?

Questo è ancora più leggibile:

setVoltage(FLUX_CAPACIATOR_CHANNEL, 4); // Puts 4V on the Flux Capaciator -- Captain Obvious
    
risposta data 30.09.2014 - 10:54
fonte
4

Partendo dal presupposto che le implementazioni sarebbero molto simili, suggerirei di avere una funzione così per il bene di ASCIUTTO . È tuttavia anche legittimo utilizzare le funzioni wrapper attorno a questa funzione per rendere il tuo codice più leggibile immediatamente

    
risposta data 30.09.2014 - 10:24
fonte
4

Dipende dal contesto. Entrambe le opzioni hanno i suoi pro e contro e i compromessi devono essere fatti.

Entrambi contemporaneamente

Libertà di scelta - che consente setChannelOneVoltage(220) e setVoltage(1, 220) .

Tutti sono felici!

Ma invita incoerenza . Un programmatore userà il primo, forse inconsapevole della scorciatoia, un altro preferirà quest'ultimo.

Il terzo programmatore arriva, cerca tutti gli usi di setChannelOneVoltage (per qualche motivo) e potrebbe non capitare che stia trascurando setVoltage(1... di chiamate.

È un dealbreaker? No, ma dovrebbe essere preso in considerazione. Ogni scorciatoia facoltativa verrà utilizzata in modo incoerente e quindi aggiungerà un po 'di rumore.

Un mio problema è la coesistenza di collection.size() == 0 e collection.isEmpty() , ad esempio. È rumoroso . Ma dal momento che entrambe le opzioni sono ugualmente valide, l'applicazione di una convenzione coerente è difficile, in quanto si riduce a un gusto in definitiva.

Solo i metodi di scelta rapida

Ora stiamo nascondendo l'implementazione setVoltage(x e rendiamo accessibile solo tramite le nostre scorciatoie per lo zucchero.

E se fosse necessario impostare rapidamente la tensione su tutti i canali? Invece di un semplice ciclo, ora stai scrivendo:

setChannelOneVoltage(voltage)
setChannelTwoVoltage(voltage)
setChannelThreeVoltage(voltage)
setChannelFourVoltage(voltage)

Va bene, possiamo racchiuderlo in un'altra funzione di scorciatoia: setAllChannelsVoltage .

E se fosse necessario impostare tutti i canali separatamente dal numero 1? Seguiamo un altro metodo di supporto: setAllChannelsButTheFirst...

A seconda della natura dell'attività, potrebbe essere difficile da mantenere .

Solo il metodo parametrico non elaborato

Ora è difficile trovare tutti gli usi di setVoltage(1... . Devi ricorrere alla ricerca di testo e fallire in caso di i = 1; setVoltage(i, 220) o qualche altra delle infinite possibilità.

Rende il codice più astratto e aggiunge al numero di parametri - se è una scelta tra uno o due, non è un grosso problema, ma se il numero di parametri è già passato oltre, dovresti pensarci due volte ogni volta prima di aggiungerne solo uno.

Se ci sono solo 4 canali e non più, setVoltage(int channel mette il codice a rischio fuori dalle eccezioni , che sei protetto da per design se fornisci solo scorciatoie.

Il codice che contiene setVoltage(5 verrà compilato e arrestato in runtime , ma non verrà generato affatto se contiene una chiamata a setChannelFiveVoltage poiché il metodo non esiste, rendendo errore molto più facile da individuare.

Per riassumere

Scegliere uno di questi approcci progettuali ci richiede di rispondere a determinate domande.

L'impostazione della tensione sul canale 2 o 3 è un caso speciale a sé stante in modo che potremmo volerlo identificare in codice e distinguere facilmente da tutti gli altri?

È probabile che dovremo iterare su questi canali e impostare la tensione in modo condizionale?

O che dovremmo impostare la tensione di un canale il cui numero ordinale è calcolato o derivato da altri dati?

La versione parametrizzata è stata già in uso per un po 'di tempo? In tal caso l'incoerenza risultante ci colpirà più strong, perché il codice preesistente non utilizzerà le scorciatoie e altri programmatori non saranno utilizzati nemmeno da loro, e rimarranno fedeli a ciò che sanno.

In altre parole - quale dei pro e contro che ho elencato sopra si applica alla tua situazione e fino a che punto? Alcuni possono essere rilevanti, mentre altri non così tanto. Calcola i compromessi per il compito in corso, non c'è nessun proiettile d'argento qui; YMMV.

    
risposta data 30.09.2014 - 11:01
fonte
3

Se stai usando un linguaggio orientato agli oggetti, avrebbe senso rendere il canale un oggetto?

channels = new Channel[4];
channels[0] = new Channel();
...
channels[0].SetVoltage(220);
    
risposta data 30.09.2014 - 10:58
fonte
3

Potresti utilizzare un'enumerazione per il tuo canale:

enum Channel
{
    C1,
    C2,
    C3,
    C4
};

quindi puoi utilizzare un singolo metodo:

setVoltage(Channel.C1,voltage);
setVoltage(Channel.C2,voltage);
setVoltage(Channel.C3,voltage);
setVoltage(Channel.C4,voltage);

e puoi utilizzarlo in un ciclo:

for(Channel channel = Channel.C1; channel <= channel.C4; channel++)
{
    setVoltage(channel,voltage);
}
    
risposta data 30.09.2014 - 13:31
fonte
0

Entrambi.

Utilizza le funzioni wrapper con pochi parametri per creare l'intuitività, chiama una singola funzione con molti parametri all'interno dei wrapper per fornire un codice compatto e coerente.

    
risposta data 30.09.2014 - 10:23
fonte
0

La domanda è duplice. Per l'esempio corrente e l'insieme di circostanze date, utilizzare l'approccio 2. In un senso più generale, la risposta sarebbe "dipende" e ci sono più approcci che solo due.

Altre varianti sull'argomento:

Approccio 3

setVoltage( channel, voltage)
setMaxCurrent( channel, maxCurrent)
setMaxWorkingTime( channel, maxHours)
setChannelSettings( channel, voltage, maxCurrent = null, maxHours = null) 

Questo è buono se entrano in gioco solo pochi argomenti. Diventa rapidamente brutto con più di 3 o 4 argomenti.

Approccio 4

struct settings {
  int channel
  nullable double voltage
  nullable double maxCurrent
  nullable double maxHours
  // add new fields here
}

setVoltage( List<settings> settings)
setVoltage( settings)

Facilmente estensibile, può essere reso compatibile in avanti, ma richiede al chiamante di impostare una struttura piuttosto complessa per ogni chiamata. L'elenco < > la versione consente di impostare tutti i valori con una chiamata, che può essere importante se la chiamata è costosa, ad es. se è un RPC con latenze elevate.

... e così via. Come vedi, tutti gli approcci hanno i loro vantaggi e svantaggi e la domanda Quale opzione è migliore? dovrebbe sempre essere completata con Quale opzione è migliore per lo scopo specifico, utilizzare il caso e il set di restrizioni che affrontiamo? .

    
risposta data 30.09.2014 - 11:23
fonte
0

Supponendo che tutti i canali siano uguali, setChannelOneVoltage (tensione) e setChannelTwoVoltage (tensione) stanno facendo lo stesso, ma su canali diversi. Se ora puoi identificare facilmente quei canali con una funzione che considera il numero del canale come argomento, il secondo approccio, utilizzando setVoltage (channelNo, voltage) sarebbe il migliore, principalmente a causa di DRY e flessibilità.

Se l'identificazione dei canali è più complessa (e forse diversa per ogni canale), dovresti considerare di avvolgere ciascun canale in un oggetto. Ma poi di nuovo, il secondo approccio sarebbe il migliore, ora con setVoltage (channelObj, voltage).

Ma se l'impostazione della tensione è significativamente diversa per ciascun canale, il primo approccio sarebbe migliore; avere una funzione / metodo distinto per ogni canale è meglio di un costrutto come

setVoltage( channel, voltage )
{
   switch( channel )
   {
      case 1: // do it for channel 1
        // Lengthy, complex code going here ...
      case 2: // do it for channel 2
        // Lengthy, complex code going here ...
      ...
   }
}

Ma per convenienza , puoi offrire un metodo setVoltage (canale, tensione) anche in questo scenario; chiama i metodi SetChannel # Voltage (voltage) in uno switch - o usando reflection, se il tuo linguaggio di programmazione fornisce tale caratteristica - in C, puoi implementare qualcosa del genere come una macro.

Un approccio alternativo per un linguaggio orientato agli oggetti sarebbe quello di definire una classe di interfaccia di canale e setVoltage (tensione) come uno dei metodi. Ciò farebbe riferimento a DRY e flessibilità, nonché a tutte le distinzioni che i diversi canali potrebbero avere nel reperimento e / o nell'impostazione della tensione.

    
risposta data 30.09.2014 - 14:26
fonte
-1

Se stai usando c #, crea un metodo di estensione. questo ti permetterebbe di fare questo:     var channel1 = new channel (...);     channel1.SetVoltage (15);

var channel2 = new channel();
channel2.SetVoltage(56);

qualche altra informazione sui metodi di estensione: link

    
risposta data 30.09.2014 - 14:44
fonte

Leggi altre domande sui tag