Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Java OOP: esercizi con Template Method Pattern e Decorator Pattern

In questo articolo vedremo un esempio pratico di utilizzo in java dei pattern Template Method (a cui l'articolo è dedicato) e Decorator (che simulremo, per esercizio)
In questo articolo vedremo un esempio pratico di utilizzo in java dei pattern Template Method (a cui l'articolo è dedicato) e Decorator (che simulremo, per esercizio)
Link copiato negli appunti

In questo articolo proseguiamo con l'approfondimento "pratico" di temi legati alle best practice OOP in ambito java, stavolta dedicandoci all'utilizzo del Template Method Pattern.

I Pattern sono come sappiamo delle linee guida da seguire per ottenere codice di qualità, ma il loro utilizzo non è prescrittivo e possono pertanto essere utilizzati in diversi modi, e con maggiore o minore difficoltà. Nel nostro caso utilizzeremo Il Template Method "simulando" un altro pattern esistente, cioè il Decorator Pattern, per aggirare alcuni aspetti negativi e difficoltosi che possono presentarsi nell'utilizzo di quest'ultimo. Ma procediamo con ordine.

Esempio con il Decorator Pattern

Facciamo prima di tutto un semplice esempio di Decorator Pattern, apriamo MyEclipse e creiamo un java project che chiamiamo ProjectTMP, creiamo un package com.decorator creiamo quindi la nostra interfaccia, e la relativa classe di implementazione:

package com.decorator;
public interface IComponent {
	public void doStuff();
}
package com.decorator;
public class Component implements IComponent {
	public void doStuff() {
		System.out.println("Do Suff");
	}
}

Il pattern Decorator ha come finalità l'aggiunta una (o più) funzionalità a livello di metodo ad una classe già esistente: dovremmo quindi preoccuparci di definire una opportuna interfaccia (sufficientemente generica):

package com.decorator;
public interface Decorator extends IComponent {
    public void addedBehavior();
}

ed implementare una classe su di essa che riutilizzi la classe precedente:

package com.decorator;
public class ConcreteDecorator implements Decorator {
	IComponent component;
	public ConcreteDecorator(IComponent component) {
		super();
		this.component = component;
	}
	public void addedBehavior() {
		System.out.println("Decorator does some stuff too");
	}
	public void doStuff() {
		component.doStuff();
		addedBehavior();
	}
}

Decorator Method Pattern

Decorator Method Pattern

Aggiungiamo per completezza una piccola classe di test:

package com.decorator;
package com.decorator;
public class Client {
	public static void main(String[] args) {
		IComponent comp = new Component();
		Decorator decorator = new ConcreteDecorator(comp);
		decorator.doStuff();
	}
}

Prima di fare qualche considerazione su quanto scritto finora, vediamo l'output prodotto dalla console:

console output

console output

É interessante fare un po' di riflessioni sul codice appena prodotto:

  • la classe Decorator non può esistere senza Component (non è vero l'opposto). Consideriamo inoltre la necessità di istanziare il riferimento al Component all'interno di Decorator: che venga fatto o meno attraverso l'Inversion of Control (così da limitare l'accoppiamento della classe), va comunque fatto.

  • C'è un basso livello di coesione nelle due classi, in sostanza Decorator aggiunge funzionalità alla
    classe Component, e dovremo quindi pensare a Decorator come la classe cui fare riferimento, invece che
    Component. D'altro canto se pensiamo a Decorator come una "evoluzione" di Component, ci ritroviamo con la situazione paraddosale di due classi che ne rappresentano una! Con metodo molto semplice l'aggiunta di funzionalità comporterebbe l'aggiunta di altri metodi e classi.

    Tanto per proseguire nella nostra idea, cercando di generalizzarla e di aggirare i problemi emersi, possiamo pensare di utilizzare un altro pattern, il Template Method Pattern.

    Rifattorizziamo l'esempio con il Template Method Pattern

    Creiamo un altro package e chiamiamolo com.tmpatternRev. Senza fare riferimento in maniera precisa all'esempio precedente, creiamo la seguente classe:

    package com.tmpatternRev;
    public abstract class Clazz1 {
    	protected abstract void foo1();
    	public void executeBusinessLogic() {
    		System.out.println("executeBusinessLogic Clazz1");
    		foo1();
    	}
    }

    Quindi sfruttiamo il Template Method Pattern creando una clas che estende la precedente in questo modo:

    package com.tmpatternRev;
    public abstract class Clazz2 extends Clazz1 {
    	protected void foo1() {
    		System.out.println("called foo1() from Clazz1!");
    	}
    	protected abstract void foo2();
    	public void executeBusinessLogic() {
    		super.executeBusinessLogic();
    		System.out.println("executeBusinessLogic Clazz2");
    		foo2();
    	}
    }

    Facciamo caso a cosa succede: Clazz1 ha un metodo che ritroveremo in tutte le classi figlie (executeBusinessLogic()), il quale stampa il messaggio executeBusinessLogic Clazz1, stampa e richiama il metodo abstract foo1(), la cui implementazione è fornita dalla classe figlia Clazz2.

    Quest'ultima a sua volta fa la stessa cosa, solo che nel metodo executeBusinessLogic() richiama
    il corrispondente della superclasse e vi aggiunge un metodo rappresentato da foo2(). Questa infine Clazz3:

    package com.tmpatternRev;
    public abstract class Clazz3 extends Clazz2{
    	protected void foo2() {
    		System.out.println("called foo2() from Clazz2!");
    	}
    	public void executeBusinessLogic() {
    		super.executeBusinessLogic();
    		System.out.println("executeBusinessLogic Clazz3");
    	}
    }

    Aggiungiamo infine la classe di test:

    package com.tmpatternRev;
    public class Test {
    public static void main(String[] args) {
    	BusinessClass bc = new BusinessClass();
    		bc.executeBusinessLogic();
    	}
    }

    console output

    console output

    Abbiamo raggiunto il nostro scopo e migliorato un po' l'implementazione.

Ti consigliamo anche