Come progettare il mio codice in modo che possa utilizzare informazioni alternative per aiutare a creare un oggetto

4

Ho una classe chiamata Product , che prende un numero di modello di prodotto e il numero di ruote per quel prodotto come parte delle informazioni di creazione, e quindi crea un'istanza del prodotto eseguendo un calcolo sul numero di ruote e su varie parametri di base

Ad esempio, Product(5, 22) crea un prodotto modello 5 con 22 ruote su di esso, dove il peso e le dimensioni di quel particolare prodotto sono calcolati dal numero di ruote e dalle specifiche di base per quel numero di modello . In questo momento le specifiche di base fanno parte della classe stessa e sono codificate nella classe, insieme alle formule di calcolo.

Il mio problema: nel codice (legacy) con cui sto lavorando, non posso sempre usare direttamente il numero del modello. Potrebbe non essere disponibile. Invece, viene dato un product_id non correlato, in cui il collegamento tra product_id e model_number è nel database.

Voglio mantenere la mia classe il più semplice possibile. Pertanto non voglio introdurre un altro costruttore che consenta product_id come parametro di input, oltre al model_number esistente, in quanto sarà la duplicazione del codice. Inoltre, non sono troppo entusiasta di inserire la logica del database all'interno della classe, ma forse posso, a pensarci ora, questo può essere un buon candidato per una classe di database-wrapper, cioè un record attivo (dove le mie specifiche di base possono essere spostate fuori dal codice e nel database).

Domanda: Come creo e restituisco l'oggetto seguendo i buoni principi orientati agli oggetti quando il model_number I in genere utilizzo per la sua creazione non è disponibile, ma un altro parametro è invece disponibile ( product_id in questo caso), che collega 1: 1 a model_number ?

Esempi di soluzioni che non mi piacciono:

  • Non coinvolgere il database - poiché al momento sto lavorando con pochi prodotti e i prodotti non cambiano spesso, posso creare una "funzione di conversione" che funge da mappa tra product_id e model_number e non toccare il database. Allo stesso modo, crea un oggetto Convert con la stessa funzionalità e usalo prima di creare l'oggetto. Problema: duplicazione della funzionalità DB nel codice.
  • Inserisci la funzionalità DB nel codice e aggiungi un costruttore alternativo. Problema: più punti di entrata della creazione del prodotto per la classe creano la duplicazione del codice.

Aggiornamento:

Ci sono fondamentalmente 3 aspetti qui:

  • dati di base (se codificati o parte del database)
  • trovare i dati di base in base a vari parametri, ovvero il numero di modello o altre informazioni identificative
  • facendo il calcolo usando i dati di base come per il numero di modello
posta Dennis 24.03.2014 - 20:37
fonte

5 risposte

1

Mi piacerebbe sviluppare la soluzione che @TMN sta presentando e prenderla un po 'oltre per rispondere al tuo problema SRP. Inserire il codice del database all'interno di ProductFactory non sarebbe sensato quindi per incapsulare questa responsabilità è possibile creare una classe separata ProductModelNumberProvider con un solo metodo findByProductId(int productId) .

Il ProductFactory dovrebbe fornire un setter setProductModelNumberProvider(ProductModelNumberProvider lookupProvider) che assegnerà il provider internamente e chiamerà findByProductId() quando appropriato.

Avrai un ProductFactory responsabile della creazione del prodotto e un ProductModelNumberProvider che eseguirà l'interazione del database, se necessario.

Avere un'occhiata alla tua domanda StackOverflow per un esempio più concreto.

    
risposta data 25.03.2014 - 19:14
fonte
6

Forse crei un ProductFactory , con metodi per creare un Product dato un numero di ruote e un ID prodotto o un numero di modello. Dato un numero di modello, si rimette al costruttore della classe e, se viene fornito un ID prodotto, esegue la ricerca DB, ottiene il numero del modello, quindi rimanda al costruttore della classe.

    
risposta data 24.03.2014 - 20:54
fonte
2

Non vuoi duplicare la mappatura del DB product_id -> model_number codificando la logica, questo ha senso. Quindi la prima cosa di cui hai bisogno è una funzione come

int mapProductIdToModelNumber(int product_id)

che esegue questa mappatura ottenendo le informazioni dal database (prendere in considerazione la memorizzazione nella cache quando questa funzione viene utilizzata molto spesso).

Ciò che rimane è come rendere questa funzione disponibile per la tua classe Product senza accoppiamento stretto. Hai le seguenti alternative:

  • passa la funzione direttamente ai blocchi di codice ogni volta che viene creato Product oggetti (dipende dal tuo linguaggio di programmazione come farlo)

  • implementa la funzione in una classe ProductFactory . Ricava ProductFactory da un'interfaccia IProductFactory e passa un oggetto di questo tipo alle aree di codice in cui al momento desideri un new Product() . Utilizza la fabbrica come suggerito da @ TMN.

In questo modo, il tuo codice legacy rimane disaccoppiato dal database, poiché non dipenderà direttamente da un ProductFactory legato al database, solo da IProductFactory , che può essere facilmente deriso (ad esempio, a scopo di test ).

    
risposta data 24.03.2014 - 21:49
fonte
1

Forse questo - rinuncia all'idea di una classe Product e crea un wrapper DB dove dirò $pf = ProductFinder() , poi fai $pf->findById() e $pf->findByModel() se necessario. Problema: dove inserisco il mio codice calcolo ? Non può essere nello stesso posto, in quanto viola il Principio di Responsabilità Singola. alias, il calcolo e la gestione dei dati dovrebbero essere separati. Quindi forse Product class può essere la parte computazionale e ProductFinder essere la parte di estrazione del database.

    
risposta data 24.03.2014 - 20:37
fonte
0

Quello che ho finito per fare:

All'inizio mi stavo chiedendo se sto meglio con una tale complessità.

Il modo più semplice era:

C'è un altro schema qui che potrei usare che mantiene le cose in una classe: link . Breaks SRP.

$product = Product::fromProductId($productId, $wheels);

Modo SRP (scelto)

  • ProductData class che ha solo i dati (può essere scambiato dal database più tardi)
  • ProductFactory class che utilizza la classe Provider per cercare il numero di modello
  • ProductNumberProvider class che fornisce il numero del modello quando viene fornito l'id prodotto
  • Product class che carica i dati del prodotto e calcola i calcoli

Codice:

$provider = new ProductModelNumberProvider();
$factory = new ProductFactory($provider);
$product = $factory->constructFromProductId($productId, $wheels);
    
risposta data 25.03.2014 - 22:21
fonte

Leggi altre domande sui tag