Ecco un problema in cui mi imbatto frequentemente: ci sia un progetto di negozio web che abbia una classe di prodotto. Voglio aggiungere una funzione che consente agli utenti di pubblicare recensioni su un prodotto. Quindi ho una classe di revisione che fa riferimento a un prodotto. Ora ho bisogno di un metodo che elenchi tutte le recensioni su un prodotto. Ci sono due possibilità:
(A)
public class Product {
...
public Collection<Review> getReviews() {...}
}
(B)
public class Review {
...
static public Collection<Review> forProduct( Product product ) {...}
}
Guardando il codice, sceglierei (A): non è statico e non ha bisogno di un parametro. Tuttavia, ho la sensazione che (A) violi il Principio di Responsabilità Unica (SRP) e il Principio Open-Closed (OCP) mentre (B) no:
-
(SRP) Quando voglio cambiare il modo in cui le recensioni vengono raccolte per un prodotto, devo cambiare la classe del prodotto. Ma dovrebbe esserci una sola ragione per cambiare la classe del prodotto. E non sono certamente le recensioni. Se impacchetta tutte le funzionalità che hanno qualcosa a che fare con i prodotti nel Prodotto, presto verrà rumorosa.
-
(OCP) Devo cambiare la classe Product per estenderla con questa funzione. Penso che questo violi la parte "chiusa per il cambiamento" del principio. Prima di ottenere la richiesta del cliente per l'implementazione delle recensioni, ho considerato Prodotto come terminato e "chiuso".
Che cosa è più importante: seguire i principi SOLID o avere un'interfaccia più semplice?
O sto facendo qualcosa di sbagliato qui del tutto?
Risultato
Wow, grazie per tutte le tue fantastiche risposte! È difficile sceglierne una come risposta ufficiale.
Consentitemi di riassumere gli argomenti principali delle risposte:
- pro (A): l'OCP non è una legge e anche la leggibilità del codice è importante.
- pro (A): la relazione dell'entità dovrebbe essere navigabile. Entrambe le classi potrebbero conoscere questa relazione.
- pro (A) + (B): esegui entrambi e delegati in (A) a (B) in modo che il Prodotto sia meno probabile che venga cambiato di nuovo.
- pro (C): metti i metodi finder in terza classe (servizio) dove non è statico.
- contra (B): impedisce il mocking nei test.
Alcune altre cose che i miei colleghi al lavoro hanno contribuito:
- pro (B): il nostro framework ORM può generare automaticamente il codice per (B).
- pro (A): per ragioni tecniche del nostro framework ORM, in alcuni casi sarà necessario cambiare l'entità "chiusa", indipendentemente da dove si trova il finder. Quindi non sarò sempre in grado di attenermi a SOLID, comunque.
- contra (C): molto chiasso; -)
Conclusione
Sto usando entrambi (A) + (B) con delega per il mio progetto corrente. In un ambiente orientato ai servizi, tuttavia, andrò con (C).