Principi OOP e nomi dei metodi

20
class Boxer:

    def punch(self, punching_bag, strength):
        punching_bag.punch(strength)


class PunchingBag:

    def punch(self, strength):
        print "Punching bag punched with strength", strength

boxer = Boxer()
punching_bag = PunchingBag()

boxer.punch(punching_bag, 2)

Non ci sono dubbi sul fatto che punch sia un buon nome di metodo nel caso di un pugile. Ma il nome punch vale anche per il metodo del sacco da boxe? In entrambi i casi intendo pugno come comando (ad esempio, punzone).

    
posta clime 04.05.2013 - 01:49
fonte

9 risposte

21

Una buona regola empirica è che i nomi dei metodi devono essere verbi o predicati tali che l'oggetto su cui li si chiama ( self nella convenzione standard di Python, this nella maggior parte delle altre lingue) diventa l'oggetto.

Con questa regola, file.close è in qualche modo sbagliato, a meno che tu non vada con il modello mentale che il file si chiude da solo, o che l'oggetto file non rappresenti il file stesso, ma piuttosto un handle di file o qualche sorta di oggetto proxy.

Un sacco da boxe non si prende mai pugni, quindi punchingBag.punch() è sbagliato in entrambi i modi. be_punched() è tecnicamente corretto, ma brutto. receive_punch() potrebbe funzionare o handle_punch() . Un altro approccio, molto popolare in JavaScript, consiste nel trattare tali chiamate di metodo come eventi, e la convenzione deve essere associata al nome dell'evento, preceduto da "on", in modo che sia on_punched() o on_hit() . In alternativa, è possibile adottare la convenzione secondo cui i participi passati indicano la voce passiva e, con tale convenzione, il nome del metodo sarebbe solo punched() .

Un altro aspetto da considerare è se il sacco da boxe sa davvero cosa lo ha colpito: fa la differenza se lo colpisci, lo batti con un bastone o lo incontri con un camion? Se è così, qual è la differenza? Riesci a far bollire la differenza su un argomento o hai bisogno di metodi diversi per i diversi tipi di punizione ricevuta? Un singolo metodo con un parametro generico è probabilmente la soluzione più elegante, perché mantiene basso il grado di accoppiamento, e tale metodo non dovrebbe essere chiamato punched() o handle_punch() , ma piuttosto qualcosa di più generico come receive_hit() . Con questo metodo, puoi implementare tutti i tipi di attori che possono colpire i sacchi da boxe, senza cambiare il sacco da boxe stesso.

    
risposta data 04.05.2013 - 10:02
fonte
6

Penso che sia un problema concettuale (come pensiamo al mondo). Va bene dire:

  • Guarda, la porta si sta chiudendo. door.close()
  • Wow, la carta si piega da sola. paper.fold()
  • Che diavolo ?! Quel file sulla scrivania si è appena chiuso, nessuno è in giro. file.close()

È strano dire:

  • Quel sacco da boxe in palestra si è appena bucato. bag.punch()

Avrebbe bisogno di avere qualcosa con cui pugnare in primo luogo (ad esempio le braccia). Probabilmente diresti:

  • Il sacco da pugilato ha iniziato a muoversi da solo, come se qualcuno lo avesse colpito. punching_bag.move()

Va bene che gli oggetti programmatici facciano cose che normalmente gli altri fanno a / con loro (nel "mondo reale"). Ma immagino che dovrebbe sempre dare almeno un senso al fatto che la cosa lo sta facendo a / con se stesso . Dovresti essere in grado di immaginarlo facilmente senza diventare oscuro (come nel caso di punching_bag ).

    
risposta data 05.05.2013 - 12:04
fonte
2

È una questione di gusti, penso. Il metodo Punching bag di punch() è almeno coerente con file.close() o frame.move() nel senso di esperire l'azione su se stesso. Maggiore domanda sarebbe, perché Boxer ha il metodo punch(something) del tutto?

    
risposta data 04.05.2013 - 02:14
fonte
2

Hai due messaggi diversi: uno per comandare un oggetto da perforare e uno per informare un oggetto che è stato perforato. Considera che probabilmente un oggetto Boxer dovrà rispondere a entrambi . A differenza . Questa è una buona ragione per dare loro nomi diversi.

La mia inclinazione sarebbe quella di mantenere punch(boxer, object, strength) e rinominare il metodo opposto in punched . Potresti chiamarlo handle_punch o qualcosa del genere ma poi è ancora ambiguo se deve gestire un comando di punzonatura o la notifica che è stato punzonato.

    
risposta data 04.05.2013 - 07:44
fonte
2

Il tuo approccio alla fine porterà a un codice molto accoppiato.

Per riassumere Eric Lippert idealmente qui vorresti il pugile essere in grado di dare un sacco di cose. Avere il sacco da pugilato come la firma della funzione boxer implica che il pugile viene creato con una conoscenza immediata di Tutto (che è punzonabile). Inoltre dare un pugno e ricevere un pugno sono due cose MOLTO diverse, quindi non dovrebbero condividere lo stesso nome.

Preferirei modellarlo come un Boxer che crea un pugno (un altro oggetto che contiene la forza dell'attributo del punzone, la portata, la direzione, ecc.)

Quindi il sacco da boxe con un metodo come onPunch che riceve questo oggetto da punzone può calcolare l'effetto del pugno su se stesso.

Tenendo presente questo il nome delle cose conta molto. Deve adattarsi al modello mentale che hai della situazione. Se ti ritrovi a cercare di spiegare come può accadere qualcosa che non ha senso a prima vista, o se hai il momento più difficile di nominare qualcosa, forse il tuo modello è sbagliato e deve cambiare.

È difficile cambiare un modello dopo l'avvio, generalmente le persone tendono a piegare la realtà per adattarla al modello. Il problema è che mentre pieghi le cose per adattarle (come un sacco da box che può colpire le cose) il mondo che stai creando diventa sempre più complesso e le interazioni diventano sempre più difficili da implementare. Alla fine raggiungerai un punto in cui aggiungere anche la cosa più banale diventa un incubo di cambiamenti e bug. Questo debito tecnico concettuale può avere un prezzo molto elevato anche se il costo iniziale era percepito come la cosa più economica da fare.

    
risposta data 18.10.2016 - 16:35
fonte
1

Questo è il problema che io chiamo "oggetto / soggetto" ed è piuttosto diffuso.

Le frasi generalmente hanno un soggetto che fa il verbo sul loro oggetto di destinazione.

Ora, per quanto riguarda la programmazione, l'unica cosa che fa realmente le cose è il computer. O praticamente un processo, un filo o una fibra. Gli oggetti non sono animati per impostazione predefinita. Non hanno i loro thread in esecuzione, quindi non possono fare nulla.

Ciò significa che i metodi operano su di essi, sono il bersaglio dell'azione e non chi fa l'azione. Ecco perché li chiamiamo "oggetti" e non "soggetti"!

Quando dici File.close non è il file che si chiude da solo, è il thread corrente che chiude il file. Se dici Array.sort , il corrente thread corrente ordina l'array. Se dici HttpServer.sendRequest , il thread corrente invia la richiesta al server (non viceversa!). Allo stesso modo, PunchingBag.punch significa che il thread corrente sta perforando il sacchetto.

Questo significa che se vuoi che Boxer sia in grado di perforare, allora deve essere una sottoclasse di Thread in modo che possa fare cose come la punzonatura delle borse nella sua funzione thread.

Tuttavia a volte è anche sensato dire che il sacco da pugni si presta da solo nel caso in cui ogni oggetto abbia il proprio filo, si potrebbe desiderare di evitare le condizioni di gara e implementare le chiamate di metodo come messaggio che passa: si colpisce il sacchetto inviandolo il punch messaggio, è il thread punch in sé e poi ti rimanda il messaggio punch successful , ma questo è solo un dettaglio di implementazione.

    
risposta data 18.10.2016 - 13:56
fonte
0

Sono d'accordo che "punch" è un buon nome di metodo per la classe Boxer, in quanto (con qualche ritocco) potrebbe essere riutilizzato contro altri oggetti. Descrive anche accuratamente che un oggetto di una classe sta facendo un'azione su un altro oggetto. Tuttavia, vorrei rinominare il metodo "doPunch", per dimostrare più chiaramente la relazione.

Tuttavia, per la classe PunchingBag, trovo che il nome del metodo sia troppo vago o un po 'impreciso rispetto a ciò che accade nel metodo. Quando vedo "pugno", penso che qualcosa stia dando un pugno a qualcos'altro. Tuttavia, qui, l'oggetto PunchingBag reagisce a un pugno da un oggetto (in questo caso, un oggetto Boxer). Quindi, rinominerei il metodo qui "isPunched" per illustrare che l'oggetto sta reagendo a un pugno.

Tuttavia, questa è la mia interpretazione di come definirei i metodi. È tutta una questione di gusti e quali standard stai seguendo.

    
risposta data 04.05.2013 - 02:14
fonte
-2

Hmmmm. sto interrogando il sacco da boxe come classe, perché non ti importa del sacco da boxe - ti preoccupi dell'impatto e della forza del pugno dei Boxers. quindi i metodi dovrebbero essere su qualsiasi cosa stia misurando e riportando l'impatto del punzone. anche se questo proviene dal "sacco da boxe", la denominazione dovrebbe comunque rivelare la responsabilità - come punchImpactMeter ecc.

    
risposta data 11.05.2013 - 00:56
fonte
-3

Il pugile pugni il sacco da boxe - > boxer.punch

Il sacco da pugilato viene colpito dal pugile - > punchingbag.get_punch

    
risposta data 21.03.2015 - 22:28
fonte

Leggi altre domande sui tag