wake-up-neo.net

Perché dovrei mai usare una catena di responsabilità su un decoratore?

Sto solo leggendo sul Chain of Responsibility pattern e sto avendo problemi a immaginare uno scenario in cui preferirei il suo uso rispetto a decorator .

Cosa pensi? Il CdR ha un utilizzo di nicchia?

67
George Mauer

Il fatto che sia possibile rompere la catena in qualsiasi momento distingue il modello di Chain of Responsibility dal pattern Decorator . I decoratori possono essere pensati come eseguendo tutto in una volta senza alcuna interazione con gli altri decoratori. I collegamenti in una catena possono essere pensati come eseguibili uno alla volta, poiché ciascuno di essi dipende dal collegamento precedente.

Usa il modello Chain of Responsibility quando puoi concettualizzare il tuo programma come una catena composta da link, in cui ogni link può gestire una richiesta o passarla sulla catena.

Quando lavoravo con l'API Win32, a volte avrei dovuto utilizzare la funzionalità di hooking fornita. L'hooking di un messaggio Windows segue in modo approssimativo il pattern Chain of Responsibility. Quando hai collegato un messaggio come WM_MOUSEMOVE, la tua funzione di callback verrebbe chiamata. Pensa alla funzione di callback come all'ultimo collegamento della catena. Ogni link nella catena può decidere se buttare via il messaggio WM_MOUSEMOVE o passarlo sulla catena al collegamento successivo.

Se il pattern Decorator fosse stato utilizzato in quell'esempio, ti sarebbe stato notificato il messaggio WM_MOUSEMOVE, ma non avresti il ​​potere di impedire ad altri hook di gestirlo.

Un altro luogo in cui viene utilizzato il pattern Chain of Command è nei motori di gioco. Ancora, puoi collegare funzioni del motore, eventi e altre cose. Nel caso di un motore di gioco, non vuoi semplicemente aggiungere funzionalità. Si desidera aggiungere funzionalità e impedire al motore di gioco di eseguire l'azione predefinita.

62
William Brendel

La differenza tra questi pattern non è legata a quando o come la catena può essere rotta (che assume una catena) o quando viene eseguito il comportamento extra. Sono collegati in quanto entrambi usano la composizione a favore dell'eredità per fornire una soluzione più flessibile.

La differenza principale è che un decoratore aggiunge nuovo comportamento che in effetti allarga l'interfaccia originale. È simile al modo in cui l'estensione normale può aggiungere metodi, eccetto che la "sottoclasse" è accoppiata solo con un riferimento, il che significa che qualsiasi "superclasse" può essere usata.

Il modello COR può modificare un comportamento esistente che è simile a sostituire un metodo esistente utilizzando l'ereditarietà. Puoi scegliere di chiamare super.xxx () per continuare sulla "catena" o gestire il messaggio tu stesso.

Quindi la differenza è sottile ma un esempio di decoratore dovrebbe aiutare:

interface Animal
{
    Poo eat(Food food);
}

class WalkingAnimal implements Animal
{
    Animal wrapped;
    WalkingAnimal(Animal wrapped)
    {
        this.wrapped = wrapped;
    }

    Position walk(Human walker)
    {
    };

    Poo eat(Food food)
    {
      return wrapped.eat(food);
    }
}

class BarkingAnimal implements Animal
{
    Animal wrapped;
    BarkingAnimal(Animal wrapped)
    {
        this.wrapped = wrapped;
    }

    Noise bark()
    {
    };

    Poo eat(Food food)
    {
        bark();
        return wrapped.eat();
    }
}

Puoi vedere che possiamo comporre un animale che cammina, che abbaia ... o che in effetti aggiunge la capacità di abbaiare a qualsiasi animale. Per utilizzare direttamente questo comportamento aggiuntivo, dovremmo mantenere un riferimento al decoratore BarkingAnimal.

All BarkingAnimal abbaia anche una volta prima di mangiare, che ha cambiato la funzionalità esistente e quindi è simile a un COR. Ma l'intento non è lo stesso di COR cioè trovare un animale di molti che mangerà il cibo. L'intento qui è di modificare il comportamento.

Potresti immaginare un COR applicato per trovare un umano che porterà l'animale a fare una passeggiata. Questo potrebbe essere implementato come un elenco collegato come chained sopra o come elenco esplicito ... o qualsiasi altra cosa.

Spero che questo sia ragionevolmente chiaro!

John

17
John Patterson

Catena

Evitare di accoppiare il mittente di una richiesta Al suo ricevitore dando a più di Un oggetto la possibilità di gestire la richiesta . Incatenare gli oggetti riceventi E passare la richiesta lungo la catena Finché un oggetto non la gestisce.

vs

Decoratore

Assegna dinamicamente ulteriori responsabilità a Un oggetto. Decoratori Forniscono un'alternativa flessibile alla sottoclasse Per estendere la funzionalità .

Direi che è intorno all'ordine in cui accadranno le cose. Se li si incatena, sarà chiamato lungo la catena. Con un decoratore non ti è garantito questo ordine, solo le ulteriori responsabilità possono essere allegate.

13
Brian

Direi che una Chain of Responsibility è una forma particolare di Decorator .

9
troelskn

Decorator viene utilizzato quando si desidera aggiungere funzionalità a un oggetto.

COR viene utilizzato quando uno dei molti attori può agire su un oggetto.

A particular Decorator è chiamato a compiere un'azione, in base al tipo; mentre COR passa l'oggetto lungo una catena definita fino a quando uno degli attori decide che l'azione è completa.

COR può essere utilizzato quando ci sono più livelli di escalation a diversi gestori - ad esempio, un call center in cui il valore del cliente per la società determina se la chiamata va a un particolare livello di supporto.

6
Ragoczy

Bene, posso pensare a 2 situazioni: 

  • Non hai un oggetto principale, cioè non sai cosa fare con la richiesta dopo aver passato tutti i livelli/filtri. (qualcosa come un aspetto come catene di intercettori che non si preoccupano veramente di dove finisce la richiesta).
  • È necessario applicare selettivamente alcune pre o post processing alla richiesta. Non in un modulo di miglioramento generale come fa il decoratore. Ad esempio, i filtri potrebbero o potrebbero non essere in grado di gestire una richiesta specifica, ma l'aggiunta di un decoratore migliora sempre l'oggetto con alcune funzionalità.

Non riesco a pensare ad altro in questo momento, mi piacerebbe sentire di più in questo argomento.

4
MahdeTo

Decoratore

  1. Decorator pattern consente di aggiungere dinamicamente un comportamento a un singolo oggetto.

  2. Fornisce un'alternativa flessibile a sub classing per estendere le funzionalità. Anche se utilizza l'ereditarietà, eredita dall'interfaccia del minimo comune denominatore (LCD).

Diagramma UML per Decorator

 UML diagram for Decorator

Conseguenze:

  1. Con la decorazione è anche possibile rimuovere dinamicamente le funzionalità aggiunte.
  2. Decoration aggiunge funzionalità agli oggetti in fase di runtime che renderebbe più difficile la funzionalità del sistema di debugging.

Link utili:

Quando utilizzare il pattern Decorator?

Decorator_pattern di wikipedia

decoratore di sourcemaking

Catena di responsabilità:

Il modello di catena di responsabilità è un modello di progettazione costituito da una sorgente di oggetti di comando e una serie di oggetti di elaborazione. Ogni oggetto di elaborazione contiene la logica che definisce i tipi di oggetti comando che può gestire; il resto viene passato al successivo oggetto di elaborazione nella catena

UML Diagram

 enter image description here

Questo modello è più efficace quando:

  1. Più di un oggetto può gestire un comando
  2. Il gestore non è noto in anticipo
  3. Il gestore deve essere determinato automaticamente
  4. È auspicabile che la richiesta sia indirizzata a un gruppo di oggetti senza specificare esplicitamente il suo destinatario
  5. Il gruppo di oggetti che può gestire il comando deve essere specificato in modo dinamico

Link utili:

Chain-of-responsibility_pattern di wikipedia

chain-of-responsibility-pattern from oodesign

chain_of_responsibility from sourcemaking

Esempio di mondo reale: In un'azienda, un ruolo designato ha limiti particolari per elaborare la richiesta di acquisto. Se una persona con un ruolo designato non ha abbastanza potere per approvare la proposta di acquisto, inoltrerà il comando/richiesta al suo successore, che ha più potere. Questa catena continuerà finché il comando non viene elaborato.

2
Ravindra babu

Concordo sul fatto che dal punto di vista strutturale questi due modelli sono molto simili. Il mio pensiero riguarda il comportamento finale:

Nella classica interpretazione dell'elemento del CdR che gestisce la richiesta si spezza la catena. 

Se qualche elemento nel decoratore rompe la catena, allora sarà errato l'implementazione del decoratore, perché la parte di base del comportamento andrà persa. E l'idea del decoratore è l'aggiunta trasparente di un nuovo comportamento quando il comportamento di base rimane intatto.

1
xenn_33
  1. parola chiave "estende" - estensione statica.
  2. Motivo decoratore - estensione dinamica.
  3. Pattern Chain Of Responsibility - solo l'elaborazione di un oggetto comando con Un insieme di oggetti di elaborazione e tali oggetti non si conoscono.
1

Penso che le situazioni per applicare questi due modelli siano diverse. E a proposito, per decoratore, il decoratore dovrebbe conoscere il componente che ha avvolto. E per il CdR, i diversi intercettori non potevano sapere nulla l'uno dell'altro.

0
hewei1997

Dopo aver letto le definizioni della Gang of Four, non sono convinto che ci sia una vera differenza. (incluso per comodità)

  • Decoratore: consente l'involucro dinamico degli oggetti al fine di modificare le loro responsabilità e comportamenti esistenti
  • Catena di responsabilità: offre a più di un oggetto un'opportunità di gestire una richiesta collegando insieme gli oggetti riceventi

Wikipedia li spiega un po ', ma alcuni sono piuttosto arbitrari.

  • Decorator viene in genere implementato come Elenco collegato. Ma penso che sia troppo basso per essere considerato "parte" del modello.
  • I link Chain of Responsibility gestiscono solo i dati se sono di loro competenza; ma determinare la responsabilità e la gestione dei dati sono entrambi parte del comportamento. I decoratori possono farlo altrettanto facilmente.
  • Decoratore richiede di chiamare il delegato.
  • Un link "puro" del CdR deve chiamare il delegato solo se non gestisce i dati.

I primi due attributi in realtà non distinguono i modelli. I secondi due lo fanno, ma il modo in cui Decorator e CoR vengono solitamente implementati non impongono questi attributi: il designer spera solo che nessuno scriva un Decorator che spezzi la catena o un CoLink che continua la catena dopo aver gestito i dati.

Per implementare effettivamente questi attributi, è necessario qualcosa di simile al seguente.

Decoratore forzato:

abstract class Decorated {

public Decorated delegate;

public final Object doIt(Object args) {
    Object returnVal = behavior(arg);
    if(delegate != null) returnVal = delegate.doit(returnVal);
    return returnVal;
}

protected abstract Object behavior(Object args); //base or subclass behavior
}

Catena di responsabilità applicata: 

abstract class Link {

public Link delegate;

public final Object processIt(Obect args) {
    Object returnVal = args;
    if(isMyResponsibility) returnVal = processingBehavior(returnVal);
    else returnVal = delegate.processIt(returnVal);
    return returnVal;
}

protected abstract Boolean isMyResponsibility(Object args);

protected abstract Object processingBehavior(Object args);
}

(In alternativa, potresti semplicemente aggiungere una linea alla javadoc, se tutto ciò che desideri è assolvere te stesso dalla responsabilità nel caso in cui qualcun altro rovini il tuo progetto - ma perché lasciarlo al caso?)

0
Kevin Sagan