Dovresti anche prendere in considerazione altre buone pratiche come Preferisci la Composizione sull'ereditarietà . Quindi il mio suggerimento sarebbe simile a questo:
class CommonBehavior{
void doSomethingCommon(){
//...
}
}
interface SpecialBehavoior{
void doSomethingSpecial();
}
class SpecialBehavior1 implements SpecialBehavoior{
@Inject
private CommonBehavior commonBehavior;
@Override
public void doSomethingSpecial(){
// what ever
commonBehavior.doSomethingCommon();
// what ever more
}
}
class SpecialBehavior2 implements SpecialBehavoior{
@Inject
private CommonBehavior commonBehavior;
@Override
public void doSomethingSpecial(){
// what ever
commonBehavior.doSomethingCommon();
// what ever more
}
}
Questo sprigiona tutta la sua potenza quando combinato con il principio Tell, non chiedere! . Ciò significa che converti le tue "condizioni" il prima possibile in oggetti SpecialBehavior
(di solito in una classe Factory che usa ancora if
s e / o switch
es) e passali intorno .
my question with this is that the calling code needs to know to call the special behaviour vs the common behaviour? – Ewa
Questa è la cosa "intelligente" di eredità e dire, non chiedere! : il codice chiamante non ha bisogno di sapere . Gli oggetti passati hanno questa conoscenza.
Il codice chiamante "si divide". Crei gli oggetti SpecialBehavior
non appena i dati entrano nel tuo sistema e li passano nelle posizioni in cui vengono chiamati i metodi di un'API comune e ogni comportamento speciale è codificato nelle diverse implementazioni di tale interfaccia.
The code implies that some cases are neither special A or B, how are those dealt with? – Ewan
Anche fare "niente" è un "comportamento speciale", quindi hai bisogno di un'implementazione dell'interfaccia SpecialBehavior
per questo:
class DoNothing implements SpecialBehavoior{
@Override
public void doSomethingSpecial(){
// do nothing
}
}
Questo sembra un sacco di "glue code", ma grazie a Java ha un eye candy chiamato lambda in modo che tu possa ugualmente scrivere in questo modo:
SpecialBehavoior doNothing = ()->{;};
ok, but then shouldnt it be doSomethingCommon which calls doSomethingSpecial? – Ewan
Entrambi i modi sono possibili e dipende dalle tue esigenze.
Per quanto ho capito, il tuo "comportamento speciale" è esclusivo mutuo. In questo caso è meglio avere una istanza singola della classe CommonBehavior
passata alle singole istanze di implementazioni SpecialBehavior
. Soprattutto il requisito "DoNothing" è facile da risolvere in questo modo.
Se lo fai, viceversa, hai due lati negativi:
-
Hai bisogno di una istanza separata di CommonBehavior
come "wrapper" per ogni istanza SpecialBehavior
.
-
Non esiste un modo Tell, do ask! per impedire che venga eseguito il "comportamento comune".
Questo significa che hai bisogno di qualcosa come
if(!specialBehavior instance of DoNothing){
// do the common behavior
}
e questo è esattamente il tipo di codice che inizialmente abbiamo cercato di evitare.