Come evitare la duplicazione del codice in altre condizioni?

2

Come posso evitare l'uso duplicato di doSomethingCommon() nel seguente blocco di codice?

doSomething();

if (conditionA) {
    doSomethingSpecificToConditionA();
    doSomethingCommon();
}
else if (conditionB) {
    doSomethingSpecificToConditionB();
    doSomethingCommon();
}

doSomethingElse();

NB: Il calcolo della condizioneA e della condizioneB può essere costoso.

    
posta Ehtesham Hasan 29.07.2018 - 08:42
fonte

6 risposte

4

Chiamare doSomethingCommon() da 2 blocchi condizionali dovrebbe andare bene e tecnicamente NON duplicazione del codice, poiché solo uno dei blocchi condizionali verrà eseguito in un dato momento.

Tuttavia, se doSomethingCommon() non è già un metodo separato, devi rifattorizzarlo in un metodo e chiamare di nuovo lo stesso è NON duplicazione del codice.

    
risposta data 29.07.2018 - 09:12
fonte
4

Introdurre una funzione di gestione delle condizioni speciali:

doSomething();

handleSpecialConditions();

doSomethingElse();

...

void handleSpecialConditions()
{
   if (conditionA)
      doSomethingSpecificToConditionA();
   else if (conditionB)
      doSomethingSpecificToConditionB();
   else
      return;

   doSomethingCommon();
}
    
risposta data 30.07.2018 - 15:06
fonte
1

Considera l'utilizzo dell'eredità per evitare più condizionali in un metodo

public class SomethingA : Something
{
    public override void DoSomething()
    {
        base.DoSomething() //all the common things
        this.SpecialForASomethings();
    }
}
    
risposta data 29.07.2018 - 09:37
fonte
0

Se non vuoi estrai handleSpecialConditions() come suggerito Eternal21 (probabilmente dovresti), considera memoizing:

doSomething();

bool flagA;
if (((flagA = conditionA)) || conditionB) {
    if (flagA)
        doSomethingSpecificToConditionA();
    else
        doSomethingSpecificToConditionB();
    doSomethingCommon();
}

doSomethingElse();
    
risposta data 30.07.2018 - 20:53
fonte
-1

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:

  1. Hai bisogno di una istanza separata di CommonBehavior come "wrapper" per ogni istanza SpecialBehavior .

  2. 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.

risposta data 29.07.2018 - 13:41
fonte
-3

I controlli booleani non sono costosi:

doSomething()

if (conditionA) {
    doSomethingSpecificToConditionA();
}
else if (conditionB) {
    doSomethingSpecificToConditionB();
}

if (conditionA || conditionB) {
    doSomethingCommon();
}

doSomethingElse()
    
risposta data 29.07.2018 - 08:58
fonte

Leggi altre domande sui tag