L'accesso ai membri di livello inferiore di un aggregato per eseguire una cattiva pratica di un'operazione?

3

Attualmente sto costruendo un piccolo progetto che dovrebbe tenere traccia delle ricette. Ogni ricetta ha un sacco di informazioni, tra cui una valutazione per detta ricetta. Dal momento che la valutazione ha qualche logica aggiuntiva, la metto nella sua classe. Ora sto pensando a come chiamare un voto di voto sul mio oggetto ricetta:

public class Recipe {
    private Rating rating = new Rating();

    public Rating getRating() {
        return this.rating;
    }

    public void submitVote(int score) {
        this.rating.vote(score);
    }
}

public class Rating {
    private int numberVotes;
    private int totalScore;

    public double getAverage() {
        return totalScore / (double) numberVotes;
    }

    public void vote(int score) {
        // Assure that score is within defined boundaries, for example 0-5
        totalScore += score;
        numberVotes++;
    }
}

public class Main {
    public static void main(String[] args) {
        Recipe r = new Recipe();
        // Option 1
        r.getRating().vote(5);
        // Option 2
        r.submitVote(5);
   }
}

Quale di questi è preferibile?

    
posta Luca Fülbier 23.07.2016 - 12:35
fonte

2 risposte

10

L'opzione 2 di solito è preferita. L'opzione 1 viola la linea guida comune nota come " Law of Demeter " - significa che il tuo programma principale ora conosce in dettaglio come funziona la votazione della tua ricetta, il che rende più difficile cambiarlo se decidi di farlo in un altro modo più tardi. Questo è un esempio di accoppiamento non necessario, che di solito cerchiamo di minimizzare.

    
risposta data 23.07.2016 - 12:54
fonte
2

Oltre alla risposta molto buona di @Jules:

Forse stai pensando al processo decisionale a un livello troppo basso. Ricorda, stai cercando di fornire un'astrazione utile e completa a clienti / utenti / chiamanti. Quindi, un modo per inquadrare la domanda è, vuoi che i client / chiamanti abbiano un'API che riguarda:

  1. ricette che hanno qualche relazione con un'entità di popolarità e voti.
  2. ricette che hanno popolarità e possono essere votate

Penso che l'opzione (2) fornisca un'astrazione semplice, completa e pertinente al client / utente / chiamante; mentre l'opzione 1 pone delle domande, ad esempio qual è la (cardinalità di) rapporto tra ricetta e rating (1: 1 o 1: N o M: N), come si passa da una valutazione a una o più ricette?

P.S. Non hai dimostrato o spiegato perché hai bisogno di un oggetto di rating come entità separata. Infatti, nel tuo esempio, stai mostrando una relazione esatta 1: 1 tra ricette e valutazioni. Forse questo è un artefatto di condensare l'esempio per scopi di domanda; tuttavia, per essere chiari, hai un'altra possibilità di non usare due classi. Alcuni potrebbero obiettare che violerebbero la responsabilità singola (SRP); quindi torni a due classi dove si delegano all'altra. D'altra parte c'è una tensione con YAGNI, nell'avere due classi ora, nel caso in cui solo una di loro debba cambiare in futuro; questa tensione è in parte dovuta al fatto che sarebbe facile effettuare il refactoring in due classi nel momento in cui è necessario anziché in anticipo.

    
risposta data 23.07.2016 - 17:20
fonte

Leggi altre domande sui tag