questo modo di chiamare una funzione è una cattiva pratica?


10

Ho il codice seguente:

public void moveCameraTo(Location location){
    moveCameraTo(location.getLatitude(), location.getLongitude());
}

public void moveCameraTo(double latitude, double longitude){
    LatLng latLng = new LatLng(latitude, longitude);
    moveCameraTo(latLng);
}

public void moveCameraTo(LatLng latLng){
    GoogleMap googleMap =  getGoogleMap();
    cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, INITIAL_MAP_ZOOM_LEVEL);
    googleMap.moveCamera(cameraUpdate);
}

Penso che in questo modo elimini la responsabilità di sapere cosa è un LatLngin un'altra classe, per esempio.

E non è necessario preparare i dati prima di chiamare la funzione.

Cosa ne pensi?

Questo approccio ha un nome? È davvero una cattiva pratica?


2
Penso che tu abbia a che fare solo con l'incapsulamento usando il metodo di sovraccarico incorporato nel linguaggio. Non è buono / cattivo. Solo uno strumento che può aiutare o danneggiare il tuo codice.
bitsoflogic,

5
Se il tuo obiettivo è nascondere LatLngai clienti di questa Cameraclasse, probabilmente non vorrai moveCameraTo(LatLng)esserlo public.
bitsoflogic,

Oltre ai consigli forniti nelle risposte, questo sembra un buon posto per menzionare YAGNI. Non ne avrai bisogno. Non definire i metodi API prima che ci sia un buon caso d'uso perché ... Non ne avrai bisogno.
Patrick Hughes,

Niente di sbagliato in moveCameraToLocatione moveCameraTo/ moveCameraToCoords. Sicuramente non vorrei passare Location / lat / long tutti con gli stessi nomi.
insidesin

Risposte:


9

Si sta utilizzando la funzionalità di sovraccarico del metodo delle lingue per offrire al chiamante modi alternativi per risolvere la dipendenza dei metodi dalle informazioni sulla posizione. Stai quindi delegando un altro metodo per risolvere il lavoro rimanente di aggiornamento della videocamera.

L'odore del codice qui sarebbe se continui ad estendere la catena di metodi che chiamano metodi. Il metodo di acquisizione della posizione chiama il metodo di acquisizione doppia che chiama il metodo di acquisizione latLng che infine chiama qualcosa che sa come aggiornare la fotocamera.

Le catene lunghe sono forti solo quanto il loro anello più debole. Ogni estensione della catena aumenta l'impronta del codice che deve funzionare o questa cosa si rompe.

È un progetto molto migliore se ogni metodo prende il percorso più breve possibile per risolvere il problema che gli è stato presentato. Ciò non significa che ognuno debba sapere come aggiornare la fotocamera. Ognuno dovrebbe tradurre il proprio tipo di parametro di posizione in un tipo uniforme che può essere passato a qualcosa che sa come aggiornare la telecamera quando viene presentato questo tipo.

Fallo in questo modo e puoi rimuoverne uno senza rompere metà di tutto il resto.

Prendere in considerazione:

public void moveCameraTo(Location location){
    moveCameraTo( new LatLng(location) );
}

Questo rende LatLngil problema della latitudine e della longitudine s. Il costo è che diffonde la conoscenza di LatLngtutto. Potrebbe sembrare costoso, ma nella mia esperienza è un'alternativa preferibile all'ossessione primitiva, che è ciò che ti impedisce di stabilire un oggetto parametro .

Se Locationè refactorable ma LatLngnon lo è, considera di risolverlo aggiungendo una factory a Location:

moveCameraTo( location.ToLatLng() );

Anche questo evita piacevolmente l'ossessione primitiva.


1
Non mi sembra così male - è davvero solo una comodità per il consumatore. Se questo fosse incatenato 10 volte o se il consumatore non avesse davvero bisogno di tutte queste opzioni, lo definirei un odore di codice.
Mcknz,

1
Ma qual è l'alternativa che mette tutte le logiche per trasformare double in LagLng o Location in LagLng in ciascuna funzione?
Tlaloc-ES,

@ Tlaloc-ES meglio?
candied_orange,

@ Tlaloc-ES La "trasformazione" deve avvenire una sola volta quando le primitive vengono caricate nella logica del dominio. Succederebbe quando deserializzassi il DTO. Quindi, tutta la logica del dominio passa LatLngo Locationoggetti. Puoi mostrare la relazione tra i due con New LatLng(Location)o Location.toLatLng()se hai bisogno di passare dall'uno all'altro.
bitsoflogic,

1
@ Tlaloc-ES Lettura correlata: FlagArgument di Martin Fowler. Leggi la sezione "Implementazione aggrovigliata".
Marc.2377,

8

Non c'è nulla di particolarmente sbagliato nella tua soluzione.

Ma la mia preferenza personale sarebbe che quei metodi non fossero così utili. E complica semplicemente l'interfaccia di qualunque oggetto a cui appartengono.

Questo void moveCameraTo(double latitude, double longitude)non semplifica davvero il codice, poiché non vedo alcun problema semplicemente chiamando moveCameraTo(new LatLng(latitude, longitude));al suo posto. Questo metodo profuma anche di ossessione primitiva.

La soluzione void moveCameraTo(Location location)potrebbe essere risolta meglio dimostrando il Location.ToLatLng()metodo e chiamando moveCameraTo(location.ToLatLng()).

se questo fosse C # e se tali metodi fossero veramente necessari, li preferirei come metodi di estensione anziché metodi di istanza. L'uso dei metodi di estensione diventerebbe davvero ovvio se si provasse in astratto e si testasse l'unità di questa istanza. Poiché sarebbe molto più semplice falsificare un singolo metodo anziché più sovraccarichi con conversioni semplici.

Penso che in questo modo elimini la responsabilità di sapere cosa è un LatLng in un'altra classe, per esempio.

Non vedo alcun motivo per cui questo sarebbe un problema. Finché il codice fa riferimento alla classe che contiene void moveCameraTo(LatLng latLng), dipende comunque indirettamente LatLng. Anche se quella classe non viene mai istanziata direttamente.

E non è necessario preparare i dati prima di chiamare la funzione.

Non capisco cosa intendi. Se significa creare una nuova istanza o trasformare le classi da una all'altra, non vedo alcun problema.

Pensandoci, ritengo che ciò che sto dicendo sia supportato anche dalla progettazione API di .NET stesso. Storicamente, molte classi .NET hanno seguito il tuo approccio di avere molti sovraccarichi con parametri diversi e conversioni semplici all'interno. Ma era prima che esistessero i metodi di estensione. Le classi .NET più moderne sono più leggere nelle proprie API e se esistono metodi con sovraccarichi di parametri, vengono fornite come metodi di estensione. Il vecchio esempio è NLog ILogger che ha dozzine di sovraccarichi per la scrittura nel registro. Confrontalo con il più recente Microsoft.Extensions.Logging.ILogger che ha un totale di 3 metodi (e solo 1 se conti la registrazione stessa). Ma ci sono molti helper e varie parametrizzazioni come metodi di estensione .

Penso che questa risposta mostri che alcune lingue avrebbero strumenti per rendere il design così bello. Non conosco molto Java, quindi non sono sicuro che ci sarebbe un equivalente. Ma anche l'utilizzo di semplici metodi statici potrebbe essere un'opzione.


Non sono sicuro del perché, ma mi ritrovo a fare il tifo per questa risposta nonostante ne abbia una concorrente. Penso che tu sia appena riuscito a migliorare il punto. Il mio unico feedback sarebbe ricordare che non tutti quelli che si occupano di questo problema sono su .NET. +1
candied_orange,

@candied_orange Right. Ora che guardo meglio alla domanda di OP, sembra più Java che C #.
Euforico,

Penso che non abbia davvero alcun problema in uso moveCameraTo(new LatLng(latitude, longitude));in qualsiasi parte del progetto, ma penso che sia più chiaro usare direttamente moveCametaTo (latLng), è come un file in Java che puoi passare come stringa o come una classe Path
Tlaloc-ES,

1

Non sono sicuro di quale sia il nome proprio per questo, se ne ha uno, ma è una buona pratica. Esporre più sovraccarichi, consentendo alla classe chiamante di determinare quale set di parametri desidera utilizzare. Come dici tu, un'altra classe potrebbe non sapere cosa sia un LatLngoggetto, ma potrebbe conoscerne il contenuto Location.

Anche avere un metodo che chiama l'altro è la chiave, poiché non si desidera duplicare il codice tra questi metodi. Come hai fatto, scegli un metodo per essere quello che fa il lavoro e chiedi agli altri metodi di chiamarlo (direttamente o indirettamente)


1

Se ti dispiace usare tipi di metodi, è solo una funzione che sovraccarica i metodi, è buono.

Ma non si elimina la responsabilità di sapere cos'è un LatLng . Perché stai inizializzando LatLng latLng = new LatLng(latitude, longitude). Questa è totalmente dipendenza da LatLng. (Per capire perché l'inizializzazione è un problema di dipendenza, è possibile controllare Iniezione dipendenze ) La creazione di un metodo sovraccarico aiuta solo i clienti a cui non importa LatLng. Se vuoi dire questo, è anche buono, ma non credo che sia un approccio. Sono solo molti metodi di servizio per i clienti.

Quindi, ci sono due opzioni per progettare la tua architettura:

  1. Creare molti metodi sovraccarichi e fornirli al client.
  2. Creare alcuni metodi sovraccarichi che richiedono parametri come interfaccia o classe concreta.

Scappo il più possibile dalla creazione di metodi che necessitano di tipi primitivi come parametri (Opzione 1). Perché se la tua azienda cambia molto tempo e devi giocare con i parametri del metodo, è davvero difficile cambiare e implementare tutte le funzioni del chiamante.

Invece di questo, utilizzare le interfacce (Dependency Injection). Se pensi che sia un costo e richieda più tempo, usa le classi e fornisci i loro metodi di estensione del mapper (Opzione 2).

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.