Cambiare il percorso per rispettare la legge di Demeter

3

Ho un compito, un proprietario e un piano. I valori di carica sono mantenuti in un piano, il proprietario è su un piano particolare e l'attività conosce il suo proprietario.

Un'attività deve impostare i suoi addebiti in base alle conoscenze del proprietario. Il proprietario ha comunque bisogno di consultare un piano per farlo. Secondo la Legge di Demetra non mi è permesso fare:

class Task {

    /**
     * @var Owner
     */
    private $owner;

    public function prepareCharges() {
        $plan = $this->owner->getPlan();
        $plan->chargeFor(...);
    }

Quindi mi chiedo se questo tipo di trucco di routing sia una soluzione praticabile.

class Task {

    /**
     * @var Owner
     */
    private $owner;

    public function prepareCharges() {
        $this->owner->helpMeDoTheCharges($this);
    }

    public function doPlanCharges(Plan $plan) {
        $distanceCharge = new Money();
        $plan->chargeFor('distance', $distanceCharge);

        $fixedCharge = new Money();
        $plan->chargeFor('fixed', $fixedCharge);
    }

}

L'attività in pratica dice al suo proprietario di inviare il piano in modo che possa inviarlo messaggi.

class Plan {

    public function chargeFor($type, Money $money) {

    }

}

class Owner {

    private $plan;

    public function helpTaskDoTheCharges(Task $task) {
        $task->doPlanCharges($this->plan);
    }

}

    
posta Weltschmerz 03.02.2015 - 20:03
fonte

3 risposte

0

Suggerirei di fare qualcosa di simile al seguente:

class Task {
   public function prepareCharges() {
      $charges = new Charges();
      $distanceCharge = new Money();
      $charges->add('distance', $distanceCharge);

      $fixedCharge = new Money();
      $charges->add('fixed', $fixedCharge); 

      $this->owner->charge($charges);
   }
}

class Owner {
   public function charge(Charges $charges) {
       $this->plan->charge($charges);
   }
}

Fondamentalmente, invece di cercare di indurre in modo imbarazzante una situazione in cui hai riferimenti a tutti quegli oggetti, metti tutte le accuse all'interno di un oggetto valore e passane il proprietario.

L'intenzione della legge di Demeter è di minimizzare la conoscenza che una parte del tuo sistema ha su un'altra. Task non dovrebbe sapere Plan . Il tuo approccio di avere Owner richiama in Task con un Plan può seguire la lettera della Legge di Demetra, ma risulta in Task con conoscenza approfondita di Owner , precisamente ciò che Demeter sta provando a evitare. Faresti meglio a restituire il piano perché quel codice era più facile da seguire.

    
risposta data 23.09.2015 - 17:07
fonte
3

Solitamente useresti solo uno strato di riferimento indiretto ...

class Task {

    private $owner;

    public function prepareCharges() {
        $this->owner->chargeFor(...);
    }
...

class Owner {
    public chargeFor() {
        $plan = $this->getPlan();
        $plan.chargeFor(...)
        ...
    
risposta data 23.09.2015 - 17:10
fonte
0

Penso che dovresti rendere il proprietario responsabile della gestione dei loro addebiti e semplicemente passare l'attività al proprietario. In questo modo il compito non deve mai toccare il piano.

Non credo che la tua alternativa sia davvero molto meglio perché un compito deve ancora sapere di un piano e sapere che è responsabile della determinazione del costo.

Ecco un esempio, presumo che l'attività sia responsabile della determinazione della variabile di costo (tempo di esecuzione), che il piano sia responsabile della determinazione della tariffa per unità di costo variabile e che il cliente sia responsabile della contabilizzazione del costo accumulato nel tempo:

class Task {

    /**
     * @var Owner
     */
    private $owner;

    public function execute() {
        // Do whatever a task does
        $this->owner->charge($this);    
    }

   public function getExecutionTime() {
       return 10; // Just an example
   }
}

class Owner {

    private $plan;
    private $bill = 0;

    public function charge(Task $task) {
        $taskCost = $this->plan->calculateCost($task->getExecutionTime());
        $bill += $taskCost;
    }

}

class Plan {

    private $rate = 0.5;

    public function calculateCost($time) {
        return $rate * $time;
    }

}

Se i proprietari sono responsabili di invocare l'esecuzione dell'attività, potreste essere in grado di farla franca senza nemmeno passare il proprietario all'attività, potreste semplicemente richiamare l'attività e ottenere il tempo di esecuzione dall'interno del proprietario. In questo modo l'attività non dipende da un proprietario da eseguire, anche se altri aspetti dell'attività dipendono dall'avere un proprietario, quindi non sarebbe pratico.

    
risposta data 27.03.2015 - 12:17
fonte

Leggi altre domande sui tag