Wzorce projektowe: Visitor

Podstawowym zadaniem wzorca projektowego Wizytator (Visitor) oddzielenie kodu implementującego pewien określony algorytm od obiektów różnych typów.
Przy implementacji wzorca, z reguły chodzi nie o obiekty same w sobie a o możliwość dynamicznej podmiany algorytmu.

package pl.roboczenotatki.designpatterns.visitor;

public class App 
{
    public static void main( String[] args )
    {
    	System.out.println( "Design pattern: Visitor" );
    	
    	Visitor grandmother = new Grandmother();
    	
    	Visitable father = new Father();
    	Visitable mother = new Mother();
    	
    	House house = new House();
    	house.addResident(mother);
    	house.addResident(father);
    	
    	house.visit(grandmother);
    }
}

Interfejs Visitable – interfejs implementowany przez obiekty, które otrzymują dodatkową logikę. W naszym przykładzie Ojciec, Matka

package pl.roboczenotatki.designpatterns.visitor;

public interface Visitable {
	public void accept(Visitor visitor);
}

Interfejs Visitor – ten interfejs implementować będą obiekty, (w naszym przypadku jeden obiekt Babcia) które wprowadzają algorytm (dodatkową logikę).

package pl.roboczenotatki.designpatterns.visitor;

public interface Visitor {
	public void visit(Mother visitable);
	public void visit(Father visitable);
}

House – chociaż implementuje interfejs Odwiedzany, nie dodaje dodatkowej logiki, a jedynie przekazuje ją innym zgrupowanym przez siebie obiektom. Babcia (nasz wizytator) nie odwiedza domu dla niego samego a dla domowników w nim zawartych. Dom jest jedynie opakowaniem na właściwe obiekty.
Dom może przyjąć nowego mieszkańca lub zaakceptować gościa. Jeżeli dom zaakceptuje gościa, to tym samym zaakceptują go wszyscy jego mieszkańcy.

package pl.roboczenotatki.designpatterns.visitor;

import java.util.ArrayList;
import java.util.List;

public class House {
	private List<Visitable> residents;
	
	public void addResident(Visitable resident){
		getResidents().add(resident);
	}
	
	public void visit(Visitor visitor){
		for (Visitable resident : getResidents()) {
			resident.accept(visitor);
		}
	}
	
	private List<Visitable> getResidents(){
		if(residents == null){
			residents = new ArrayList<Visitable>();
		}
		return residents;
	}
}
package pl.roboczenotatki.designpatterns.visitor;

public class Mother implements Visitable{

	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
}

package pl.roboczenotatki.designpatterns.visitor;

public class Father implements Visitable{

	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

}

package pl.roboczenotatki.designpatterns.visitor;

public class Grandmother implements Visitor{

	public void visit(Mother visitable) {
		System.out.println("Hello from Grandmother to Mother");
	}

	public void visit(Father visitable) {
		System.out.println("Hello from Grandmother to Father");
	}

}

źródło: http://blog.smentek.pl/2010/02/09/wzorzec-projektowy-wizytator/

Wzorce projektowe: Chain of Responsibility (Łańcuch zobowiązań)

Wzorzec projektowy Chains of Responsibility (Łańcuch zobowiązań) prowadzi do utworzenia łańcucha obiektów, które analizując żadanie zapewniają obsługę lub przekazują je dalej. Odpowiedzialność za przetworzenie żądania spada na obiekt, który jest do tego zadania najlepiej przygotowany.

Abstrakcyjna klasa Handler

<pre>package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public abstract class Handler implements Chainable{
	private Handler succesor;

	public void setSuccesor(Handler succesor) {
		this.succesor = succesor;
	}

	public Handler getSuccesor() {
		return succesor;
	}

	protected void forward(Request request){
		if(this.succesor != null){
			this.getSuccesor().handle(request);
		}
	}

	abstract void handle(Request request);
}

 

package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public interface Chainable {
	public void setSuccesor(Handler succesor);

	public Handler getSuccesor();
}

Handler

package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public class Mod2Handler extends Handler {

	@Override
	void handle(Request request) {
		if (request.getValue() % 2 == 0) {
			System.out.println("Podzielne przez 2");
		} else {
			forward(request);
		}
	}
}

Kolejny Handler

package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public class Mod5Handler extends Handler {

	@Override
	void handle(Request request) {
		if (request.getValue() % 5 == 0) {
			System.out.println("Podzielne przez 5");
		} else {
			forward(request);
		}
	}
}

Kolejny Handler

package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public class Mod7Handler extends Handler {

	@Override
	void handle(Request request) {
		if (request.getValue() % 7 == 0) {
			System.out.println("Podzielne przez 7");
		} else {
			forward(request);
		}
	}
}

Obiekt żądania

package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public class Request {

	private String name;
	private int value;

	public Request(String name, int value) {
		super();
		this.name = name;
		this.value = value;
	}

	public String getName() {
		return name;
	}

	public int getValue() {
		return value;
	}

}

Klient

package pl.roboczenotatki.designpatterns.chainOfResponsibility;

public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Design pattern: Chain of Responsibility" );

        Handler chainBegin = new StartHandler();
        Handler chain1 = new Mod2Handler();
        Handler chain2 = new Mod5Handler();
        Handler chain3 = new Mod7Handler();
        Handler chainEnd = new EndHandler();

        chainBegin.setSuccesor(chain1);
        chain1.setSuccesor(chain2);
        chain2.setSuccesor(chain3);
        chain3.setSuccesor(chainEnd);

        chainBegin.handle(new Request("Test 25", 25));
    }
}

Struktura tego wzorca jest bardzo prosta: obiekty typu Handler są powiązane ze sobą w postaci jednokierunkowej kolejki (albo łańcucha).

Zalety:

  • klient, przekazując żądanie, nie wie, który z obiektów Handler będzie je w rzeczywistości obsługiwał
  • możliwość elastycznego przydziału odpowiedzialności do obiektów Handle

Wady:

  • brak gwarancji obsługi żądania: kolejne ogniwa mogą zrezygnować z zajęcia się nim

Przykłady zastosowania:

  • wszelkiego rodzaju filtry

Diagram wzorca:

 

Wzorce projektowe: Interpreter

Interpreter jest wzorcem projektowym, którego zadaniem jest interpretacja poleceń innego języka. Dany język rokładany jest na części gramatyczne i potem na zorientowaną obiektowo hierarchię.

Interpreter składa się : Context: który przetrzymuje dane, które powinny poddać się interpretacji, Abstract Expression: klasa abstrakcyjna która interpretuje polecenia, …. Expression – konkretne klasy, które interpretują treść Contextu dla poszczególnych przypadków.

Interface Expression

package pl.roboczenotatki.designpatterns.Interpreter;

import java.util.Stack;

public interface Expression {

	public void interpret(Stack<Integer> context);
}

Klasa MinusExpression

package pl.roboczenotatki.designpatterns.Interpreter;

import java.util.Stack;

public class MinusExpression implements Expression {

	public void interpret(Stack<Integer> context) {
		context.push(-context.pop() + context.pop());
	}

}

Klasa PlusExpression

package pl.roboczenotatki.designpatterns.Interpreter;

import java.util.Stack;

public class PlusExpression implements Expression{

	public void interpret(Stack<Integer> context) {
		context.push(context.pop() + context.pop());
	}
}

Klasa NumberExpression

package pl.roboczenotatki.designpatterns.Interpreter;

import java.util.Stack;

public class NumberExpression implements Expression {

	private Integer i;

	public NumberExpression(Integer i) {
		super();
		this.i = i;
	}

	public void interpret(Stack<Integer> context) {
		context.add(i);
	}
}

Klasa Client

package pl.roboczenotatki.designpatterns.Interpreter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Stack;

/**
 * Wzorzec interpreter
 */
public class Client {

	public static void main(String[] args) {
		String in = "42 4 2 - +"; // zapis w ONP, powinno wyjsc 44, dla 2 2 + =
									// 4
		Stack<Integer> context = new Stack<Integer>();

		// budujemy drzewo parsowania
		ArrayList<Expression> parseTree = new ArrayList<Expression>();
		for (String s : in.split(" ")) {
			switch (s) {
			case "+":
				parseTree.add(new PlusExpression());
				break;
			case "-":
				parseTree.add(new MinusExpression());
				break;
			default:
				parseTree.add(new NumberExpression(Integer.parseInt(s)));
				break;
			}
		}

		for (Iterator iterator = parseTree.iterator(); iterator.hasNext();) {
			Expression expression = (Expression) iterator.next();
			expression.interpret(context);
		}
		System.out.println(in + " = " + context.pop());

	}
}

Diagram wzorca:
interpreter