I decoratori non sono in grado di rompere facilmente l'ISP?

6

"L'Interfaccia-Segregation Principle (ISP) afferma che nessun client dovrebbe essere costretto a dipendere da metodi che non usa."

Il motivo decoratore è un motivo di progettazione per decorare un metodo di una classe. Per questo, il decoratore implementa la stessa interfaccia dell'oggetto decorato, in modo che possa prendere il suo posto.

Ma questo non significa che deve implementare tutti i metodi nell'interfaccia, quando ne usa solo uno, quello che decora? Quindi immagino che violi l'ISP. L'unico caso è che non è quando l'interfaccia decorata contiene solo il metodo che deve essere decorato, ma io lo vedo come un caso piuttosto raro.

Un esempio potrebbe essere che ci sono pagine in un libro. Alcune pagine hanno note a piè di pagina, altre pagine hanno titoli in alto. Quindi implementiamo questi extra come decoratori di un metodo, diciamo draw (). Ma una pagina ha anche altri metodi, diciamo: fold () e tear () e altri metodi possono venire in seguito. Ma se vogliamo usare versioni decorate di pagine inserite in un libro, e lavorando allo stesso modo, finiamo per implementare in ogni decoratore ogni metodo di una pagina, dove l'unica cosa che accade è che il decoratore passa la chiamata alla pagina è contenente.

interface IPage {
    public ITearResult tear();
    public void draw();
}

class FooterDecorator implements IPage {
    private IPage page;

    public FooterDecorator(IPage page) {
        this.page = page; //the object it decorates
    }

    //violates the ISP, because it has to implement it, but it's not using it,
    //just passes the operation
    public ITearResult tear() {
        return page.tear();
    }

    //decorated method
    public void draw() {
        page.draw();
        ... draw footer - the decoration
    }
}

Non riesco a capire correttamente il modello di decorazione o l'ISP? È una violazione accettabile o questi due si contraddicono davvero?

    
posta Máthé Endre-Botond 23.04.2014 - 21:31
fonte

2 risposte

11
//violates the ISP, because it has to implement it, but it's not using it,
//just passes the operation
public ITearResult tear() {
    return page.tear();
}

Questo non è corretto. Il decoratore è utilizza il metodo tear ; è implementato secondo il suo contratto, anche se l'implementazione è semplice come delegare quel lavoro a qualcun altro. Dal punto di vista che il decoratore è il cliente dell'interfaccia originale, non ci sono problemi; l'intero punto del decoratore è di implementare l'interfaccia originale e più , quindi per definizione ha una dipendenza dall'interfaccia.

L'utente di un decoratore ha anche una dipendenza dall'interfaccia originale e dall'eventuale potenziamento fornito dal decoratore; in caso contrario, non avrebbe bisogno di un decoratore e potrebbe invece affidarsi a un'interfaccia che fornisce solo le nuove funzionalità.

Am I not understanding the decorator pattern or the ISP correctly, it's an acceptable violation or these two really contradict each other?

Non stai capendo correttamente l'ISP.

Considera un sistema con vari tipi di porte. Le porte implementano un'interfaccia Door che contiene metodi open e close . Il codice client chiama questi metodi e va tutto bene.

In seguito devi implementare un TimedDoor che si chiude da solo dopo un certo periodo di tempo (ma può ancora essere chiuso attraverso il metodo close prima che il tempo scada). Qualche codice client deve essere in grado di impostare il timeout su queste porte. Quello che ci dice il Principio di segregazione dell'interfaccia è che non dovresti aggiungere un metodo setTimeout all'interfaccia Door ; dovremmo invece definire una nuova interfaccia (diciamo, TimedObject ) che fornisce tali servizi.

Considera cosa sarebbe accadere se hai aggiunto setTimeout a Door - ora ogni porta nel sistema deve implementare quel metodo. Cosa dovrebbero fare? Tratta come un no-op ? Lanciare un'eccezione? Entrambe sono violazioni del contratto del metodo setTimeout (cioè violazioni del Principio di Subtitution di Liskov). L'unica altra opzione è indebolire il contratto dicendo che gli oggetti possono o meno implementare setTimeout , il che equivale a dire che qualcosa può o potrebbe non essere un TimedObject . Combatteresti con il sistema dei tipi e ti derubrai delle garanzie che ha lo scopo di comprarti.

Un altro (molto meno importante ma ancora sfortunato) effetto collaterale è che la modifica dell'interfaccia Door generalmente innescherebbe una ricompilazione di tutto il codice che si basava su di esso anche se quel codice non ha alcuna utilità per il metodo setTimeout .

Tenendo questo a mente, tieni presente che l'uso di un decoratore non modifica l'interfaccia originale che avvolge.

    
risposta data 23.04.2014 - 21:52
fonte
2

Potrebbe mancare un livello di astrazione nell'implementazione del decoratore. Considera la seguente alternativa:

interface IPage {
public ITearResult tear();
public void draw();
}

abstract class PageBaseDecorator implements IPage {
    protected IPage page;

    public PageBaseDecorator(IPage page) {
        this.page = page; //the object it decorates
    }

    public ITearResult tear() {
        return page.tear(); // delegate implementation to object
    }

    public void draw() {
        page.draw(); // delegate implementation to object
    }
}

class FooterDecorator extends PageBaseDecorator {

    public FooterDecorator(IPage page) {
        super(page);
    }

    // tear does not need to be implemented as it exists in PageBaseDecorator
    // and is not used by FooterDecorator

    //decorated method
    public void draw() {
        super.draw();
        ... draw footer - the decoration
    }
}

Non sono aggiornato sulla programmazione Java, quindi non sono sicuro che la sintassi sopra riportata sia corretta, ma dovrebbe darti un'idea di ciò che potresti mancare nel pattern del decoratore. Il Base Decorator non viola l'ISP perché dipende dall'intera interfaccia a cui sta delegando. I bambini del decoratore di base dovrebbero solo implementare i pezzi che decorano attivamente però.

    
risposta data 29.04.2014 - 00:07
fonte

Leggi altre domande sui tag