Wzorce projektowe: strategy

Strategia jest czynnościowym wzorcem obiektowym. Wzorzec składa się z wielu związanych ze sobą algorytmów ukrytych wewnątrz klasy sterującej zwanej Context.

Bardzo łatwo dodaje się nowe algorytmy, poprzez utworzenie nowej klasy implementującej dany interfejs. Conext może w danej chwili mieć wybraną tylko jedną strategię.

package pl.roboczenotatki.designpatterns.strategy;

public interface Vehicle {
	public void makeSound();
}

package pl.roboczenotatki.designpatterns.strategy;

public class Car implements Vehicle{

	@Override
	public void makeSound() {
		System.out.println("Brum from car");
	}
}

package pl.roboczenotatki.designpatterns.strategy;

public class Bus implements Vehicle{

	@Override
	public void makeSound() {
		System.out.println("Brum from bus");
	}
}

package pl.roboczenotatki.designpatterns.strategy;

import java.util.Calendar;

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

		Vehicle vehicle = null;
		switch (Calendar.DAY_OF_WEEK) {
		case Calendar.SATURDAY:
		case Calendar.SUNDAY:
			vehicle = new Car();
			break;
		default:
			vehicle = new Bus();
			break;
		}

		vehicle.makeSound();

	}
}

Diagram:
strategy

Reklamy

Wzorce projektowe: Simple Factory

Simple factory jest jednym z wzorców konstrukcyjnych, których zadaniem jest tworzenie obiektów. Wzorzec ten charakteryzuje się tym, że caly proces decyzyjny i konstrukcyjny jest w jednej metodzie.

package pl.roboczenotatki.designpatterns.simpleFactory;

public enum Animal {
	RABBIT, WOLF, BOAR;
}

package pl.roboczenotatki.designpatterns.simpleFactory;

public interface WildAnimal {
	public void showName();
}

package pl.roboczenotatki.designpatterns.simpleFactory;

public class Rabbit implements WildAnimal {

	@Override
	public void showName() {
		System.out.println("I'm rabbit");
	}
}

package pl.roboczenotatki.designpatterns.simpleFactory;

public class Wolf implements WildAnimal {
	@Override
	public void showName() {
		System.out.println("I'm wolf");
	}
}

package pl.roboczenotatki.designpatterns.simpleFactory;

public class Boar implements WildAnimal{

	@Override
	public void showName() {
		System.out.println("I'm boar");
	}
}

package pl.roboczenotatki.designpatterns.simpleFactory;

/** Zastosowano tutaj rowniez wzorzec Singleton */
public class AnimalFactory {
	private static AnimalFactory INSTANCE;

	private AnimalFactory(){}

	public static AnimalFactory getInstance(){
		if(INSTANCE == null){
			INSTANCE = new AnimalFactory();
		}
		return INSTANCE;
	}

	public WildAnimal createWildAnimal(Animal animal){
		switch (animal) {
		case RABBIT:
			return new Rabbit();
		case WOLF:
			return new Wolf();
		default:
			return new Boar();
		}
	}
}

package pl.roboczenotatki.designpatterns.simpleFactory;

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

    	WildAnimal wildAnimal = AnimalFactory.getInstance().createWildAnimal(Animal.RABBIT);
    	wildAnimal.showName();
    }
}

Wzorce projektowe: proxy

Proxy jest strukturalnym wzorcem projektowym wykorzystywanym do reprezentowania skomplikowanego obiektu lub obiektu, którego utworzenie wymaga dużego nakładu czasu, za pomocą obiektu prostego.

Wzorzec ten ma na celu zbudowanie klasy będącej odpowiednikiem innej klasy, pozwalając jednocześnie na zarządzanie dostępem do niej:

  • gdy chcesz wykonywać pewne zdalne obiekty(remote proxy – pełnomocnik zdalny),
  • gdy z pewnych względów nie chcesz tworzyć obiektu danej klasy aż do chwili wywołania jednej z jego metod, np. gdy z góry wiesz, że utworzenie takiego obiektu jest bardzo czasochłonne bądź zasobochłonne (virtual proxy – pełnomocnik wirtualny),
  • gdy chcesz kontrolować dostęp do pewnego obiektu twojego systemu (protection proxy – pełnomocnik ochraniający),
  • gdy poza akcją wykonywaną przez obiekt danej klasy musisz wykonać także dodatkowe akcje powiązane z jego metodą bądź metodami (smart proxy – sprytny pełnomocnik).

User

package pl.roboczenotatki.designpatterns.proxy;

public interface User {
	public String getLogin();

	public String getPass();
}

Client

package pl.roboczenotatki.designpatterns.proxy;

public class Client implements User{

	public String getLogin() {
		return "clientLogin";
	}

	public String getPass() {
		return "clientPass";
	}

}

ClientProxy

package pl.roboczenotatki.designpatterns.proxy;

public class ClientProxy implements User {
	private Client client;

	public ClientProxy() {
		super();
		this.client = new Client();
	}

	public String getLogin() {
		return client.getLogin();
	}

	public String getPass() {
		return client.getPass() + "hacked";
	}
}

App

package pl.roboczenotatki.designpatterns.proxy;

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

    	User client = new Client();
    	System.out.println("login: " + client.getLogin() + ", pass:" + client.getPass());

    	User clientProxy = new ClientProxy();
    	System.out.println("login: " + clientProxy.getLogin() + ", pass:" + clientProxy.getPass());
    }
}

Output:
Design pattern: Proxy
login: clientLogin, pass:clientPass
login: clientLogin, pass:clientPasshacked

 

Diagram:

proxy

Wzorce projektowe: Template method

Wzorzec projektowy Template method jest wzorcem operacyjnym. Definiuje on za pomocą abstrakcji szkielet algorytmu, który w klasach potomnych jest w pełni realizowany. Na początku tworzona jest klasa zawierająca ogólne kroki algorytmu zapisane jako metody abstrakcyjne. Klasy potomne nadpisują te abstrakcyjne metody implementując rzeczywiste akcje.

Dzięki takiemu podejściu szkielet algorytmu trzymany jest w jednym miejscu, a jego mniejsze kroki mogą być zmieniane w podklasach.

Template Method jest wykorzystywany we wzorcach Strategia i Abstract Factory.

package pl.roboczenotatki.designpatterns.templateMethod;

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Design pattern: Template method" );
        
        AbstractAlgorithm algorithm = new PrintAlgorithm();        
        algorithm.run();
    }
}

AbstractAlgorithm

package pl.roboczenotatki.designpatterns.templateMethod;

public abstract class AbstractAlgorithm {

	public void run(){
		before();
		doRun();
		after();
	}
	
	private void before(){
		System.out.println("Before");
	}
	
	private void after() {
		System.out.println("After");
	}
	
	protected abstract void doRun();
}

PrintAlgorithm

package pl.roboczenotatki.designpatterns.templateMethod;

public class PrintAlgorithm extends AbstractAlgorithm{

	@Override
	protected void doRun() {
		System.out.println("PrintAlgorithm is running");
	}

}

Wzorce projektowe: iterator

Różnorodność kolekcji obiektowych (listy, kolejki, stosy, zbiory, multizbiory, mapy etc.), zarówno funkcjonalna, jak i implementacyjna, powoduje, że wiele z nich wymaga specyficznej obsługi i stosowania zróżnicowanych metod dostępu do elementów. Wzorzec Iterator odpowiada na potrzebę zunifikowanego dostępu do elementów kolekcji, który pozwoli pominąć różnice w ich implementacji. Dzięki niemu, niezależnie od rodzaju kolekcji, jej elementy mogą być przetwarzane sekwencyjnie, z zachowaniem własności poszczególnych kolekcji.

Wzorce projektowe: memento

Memento jest wzorcem, którego wykorzystuje w sytuacji gdy musimy zamrozić stan obiektu w celu jego późniejszego wykonania.

Wzorzec memento składa się z trzech głównych obiektów:

  • Originator: klasa, której stan ma być przechowywany, musimy w niej implementować metody zapisujące i odczytujące stan z obiektu Memento
  • Memento: klasa, w która potrafi przechować wszystkie dane z Originatora, które muszą być utrwalone.
  • Caretaker: jest klasą która przechowuje kolekcję memento i udostępnia metody do zapisu i odczytu.

Szczególną rolę we wzorcu odgrywają dwie klasy: Originator, który jest twórcą i właścicielem wszystkich migawek stanu, oraz Memento, której obiekty przechowują stan Originatora. Obiekt Originator musi posiadać możliwość utworzenia obiektu Memento oraz odczytania jego zawartości w celu przywrócenia na tej podstawie poprzedniego stanu. Memento przechowuje stan obiektu Originator zapisany w dowolnym momencie; pozwala też na dostęp do niego obiektowi Originator, natomiast uniemożliwia operacje na migawce wszelkim innym obiektom. Przykładem jest obiekt Caretaker, który zarządza utworzonymi migawkami, natomiast nie ma dostępu do ich zawartości.

Caretaker

package pl.roboczenotatki.designpatterns.memento;

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

public class Caretaker {
	private List mementos;

	public List getMementos() {
		if(mementos == null){
			mementos = new ArrayList();
		}
		return mementos;
	}

	public void addMemento(Memento memento){
		getMementos().add(memento);
	}

	public Memento getMemento(int index){
		return getMementos().get(index);
	}

}

Memento

package pl.roboczenotatki.designpatterns.memento;

public class Memento {
	private final String state;

	public Memento(String state) {
		super();
		this.state = state;
	}

	public String getState() {
		return state;
	}

}

Originator

package pl.roboczenotatki.designpatterns.memento;

public class Originator {
	private String state;

	public Originator(String state) {
		super();
		this.state = state;
	}

	public void setState(String state) {
		this.state = state;
	}

	public String getState() {
		return state;
	}

	public Memento createMemento(){
		return new Memento(this.state);
	}

	public void restoreMemento(Memento memento){
		this.state = memento.getState();
	}

}

App

package pl.roboczenotatki.designpatterns.memento;

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

    	Caretaker caretaker = new Caretaker();
    	Originator originator = new Originator("nazwa1");

    	originator.setState("nazwa2");
    	caretaker.addMemento(originator.createMemento());
    	originator.setState("nazwa3");
    	caretaker.addMemento(originator.createMemento());
    	originator.setState("nazwa4");
    	originator.setState("nazwa5");
    	caretaker.addMemento(originator.createMemento());

    	System.out.println("Memementos:");
    	for (Memento m : caretaker.getMementos()) {
			System.out.println(m.getState());
		}

    	originator.restoreMemento(caretaker.getMemento(1));
    	System.out.println("Restore index 1: " + originator.getState());
    }
}

Diagram wzorca:
memento

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/