Pattern pattern pattern: classi astratte e delegazione dell'interfaccia

1

Il modello del metodo di modello viene comunemente implementato con classi astratte.

interface Algorithm 
{
    void perform();
}

abstract class AlgorithmBase implements Algorithm
{
    abstract void step1();
    abstract void step2();

    private void finalStep()
    {
        // common implementation
    }

    // Template method 
    public final void perform() 
    {
        step1();
        step2();
        finalStep();
    }
}

public class AlgorithmA extends AlgorithmBase
{
    void step1()
    {
        // step 1 implementation
    }

    void step2()
    {
        // step 2 implementation
    }
} 

utilizzando

  Algorithm a = new AlgorithmA();
  a.perform();

Ma alcuni linguaggi (come Swift) non supportano le classi astratte. L'implementazione del modello di metodo template viene eseguita tramite la delega dell'interfaccia.

protocol Algorithm
{
    func perform()
}

protocol AlgorithmSteps
{
    func step1()
    func step2()
}

class AlgorithmBase: Algorithm
{
    var delegate: AlgorithmSteps

    init(delegate: AlgorithmSteps)
    {
        self.delegate = delegate
    }

    private func finalStep()
    {
        // common implementation
    }

    // Template method
    final func perform()
    {
        delegate.step1()
        delegate.step2()
        finalStep()
    }
}

class AlgorithmA : AlgorithmSteps
{
    func step1()
    {
        // step 1 implementation
    }

    func step2()
    {
        // step 2 implementation
    }
}

let a : Algorithm = AlgorithmBase(delegate: AlgorithmA())
a.perform()

Ovviamente se la lingua non supporta le classi astratte l'unica strada da percorrere è l'utilizzo della delega dell'interfaccia, ma cosa succede se lo fa? Quindi, il modello di metodo del modello può essere implementato in entrambi i modi.

La seconda implementazione ha qualche vantaggio in termini di buone pratiche OOP rispetto al primo?

    
posta Dalija Prasnikar 28.11.2015 - 17:30
fonte

1 risposta

2

Nessuno dei due è migliore dell'altro. Dipende interamente dal tuo punto di vista. Nel primo caso, dovresti pensare ad estendere la logica di AlgorithmBase . Supponiamo di avere una classe chiamata DatabaseEntity con la classe PersonEntity che ne deriva. Entrambi possono essere salvati nel database, in quest'ultimo caso può essere necessario sovrascrivere la logica di convalida prima del salvataggio per garantire che vengano riempiti i valori firstName e lastName . DatabaseEntity è ancora responsabile di quando vengono richiamati questi metodi, ma PersonEntity ridefinisce il significato di convalidare quell'istanza.

Nel secondo caso, si tratta di trasferire la responsabilità a un'altra classe. Probabilmente non vorresti passare la responsabilità a un'altra classe nel caso precedente. Un'istanza PersonEntity è perfettamente adatta per eseguire la convalida di se stessa. Prendi piuttosto l'esempio di VehicleFactory . Qualsiasi classe derivante da VehicleFactory dovrebbe restituire un'istanza di Vehicle , ma si supponga di voler generare anche una persona che guida il veicolo. Sarebbe sbagliato aspettarsi che una classe derivata di VehicleFactory si preoccupi di ciò. Invece, dovrebbe avere un'istanza PersonFactory e delegare il lavoro di creazione di un'istanza Person a PersonFactory . È ancora un passaggio nel processo di creazione di Vehicle , ma in contrasto con il primo esempio, alcuni passaggi non dovrebbero essere eseguiti da quella classe o dalle sue classi derivate.

TL; DR - Dipende da cosa è necessario aver fatto e se i passaggi 1 e 2 devono essere eseguiti o meno da una classe derivata.

    
risposta data 28.11.2015 - 18:56
fonte

Leggi altre domande sui tag