È accettabile che le classi figlie "interrompano" la funzionalità della classe genitore?

5

Uno degli sviluppatori che lavora con me sta seguendo il principio aperto / chiuso per aggiungere funzionalità a un modello estendendoci dal nostro framework ORM.

class BaseModel extends ORM {
   ...
}

Tutti i nostri modelli ora ereditano BaseModel e questo modello funziona bene nel contesto della nostra applicazione.

class Product extends BaseModel {
  ...
}

Il problema si presenta quando abbiamo provato a utilizzare i modelli come se fossero estesi direttamente dall'ORM, utilizzare alcune delle funzionalità di base:

$product = Product::factory();
$product->name = 'foo';
$product->price = 9.99;
$product->save();

Questo codice avrebbe dovuto funzionare bene ma non è riuscito perché ora il metodo factory richiede un elenco di parametri.

Penso che finché i modelli funzionino bene nel contesto del nostro prodotto siamo buoni; ma ho anche sentimenti contrastanti sul non supportare alcune delle funzionalità di base della classe genitore.

Pensieri?

    
posta Onema 04.04.2013 - 18:16
fonte

4 risposte

4

Qualsiasi metodo accessibile al pubblico fa parte di un contratto su come le cose possono essere utilizzate. Con che richiede i parametri su un metodo di classe discendente, questo contratto è violato (vedi il già citato LSP).

Tuttavia, a volte è necessario aggiungere parametri. In tal caso, il metodo di sovrascrittura dovrebbe comunque essere in grado di utilizzare la firma originale. Nel tuo esempio, questo può essere ottenuto assegnando valori predefiniti adeguati ai parametri in BaseModel::factory() .

    
risposta data 05.04.2013 - 17:35
fonte
2

In generale, questo non è davvero un problema fondamentale. Rendere le classi child sovrascrive la funzionalità dei loro genitori è una caratteristica comune e spesso desiderabile di ereditarietà. È necessario soprattutto se vuoi fare qualcosa di polimorfico.

Ma questo caso è un po 'diverso - questo è un problema di cambiare la catena ereditaria delle tue classi. Quindi, in realtà, sono le modifiche al genitore ( BaseModel ) il problema.

Sembra che la tua classe BaseModel abbia modificato (sovrascritto) il metodo statico factory() aggiungendo ulteriori parametri obbligatori. Supponendo che ci sia una buona ragione per la nuova lista di parametri, penso che questo sia un cambiamento OK. È solo che questi tipi di cambiamenti possono avere un reale effetto a catena sulle classi downstream.

Ma ecco la vera domanda: perché ti stai affidando a Product per ereditare un metodo statico? Mi sembra un po 'strano, ma consente anche una potenziale soluzione. Esegui l'override di factory() nella tua classe Product , quindi non richiede parametri, se possibile. Può quindi chiamare altri metodi factory() delle classi genitore, se necessario.

    
risposta data 04.04.2013 - 18:54
fonte
1

Come già affermato da nibra, hai un contratto per questo metodo pubblico accessibile e non ti è permesso di romperlo.

Una regola davvero semplice è che, per una classe estesa, puoi estendere il tipo di input che accetti, ma essere più specifico sull'output, in modo da non interrompere il contratto.

    
risposta data 05.04.2013 - 18:10
fonte
1

Il principio di sostituzione di Liskov limita il comportamento dei metodi istanza nelle sottoclassi. Non dice nulla sui metodi di classe come Product :: factory .

    
risposta data 31.12.2015 - 19:30
fonte

Leggi altre domande sui tag