• Nie Znaleziono Wyników

Wzorce projektowe 2

N/A
N/A
Protected

Academic year: 2021

Share "Wzorce projektowe 2"

Copied!
120
0
0

Pełen tekst

(1)

Wzorce projektowe 2

Marcin Orchel

AGH University of Science and Technology in Poland

(2)
(3)

1 Diagramy UML

2 Wzorce operacyjne

(4)
(5)

Wprowadzenie do diagramów sekwencji UML

diagram sekwencji, ang. sequence diagram – typ diagramu interakcji, który koncentruje się na wymianie wiadomości pomiędzy wieloma liniami życia, diagram sekwencji opisuje interakcję za pomocą

wyszczególnienia sekwencji wiadomości, które są wymieniane, wraz ze specyfikacją.

linia życia, ang. lifeline – obiekt oraz linia poniżej

specyfikacja wykonania, ang. ExecutionSpecification – cienki prostokąt na linii życia

wiadomość, ang. message – strzałka wskazuje kierunek komunikacji, typ wiadomości call – wywołanie metody, return - powrót

(6)

:Type1 :Type2

synchCall return

asynchCall

Rysunek 1:Źródło: własne

Diagramy UML 6 / 120

(7)

Wzorce operacyjne

(8)

Pozwala uniknąć wiązania nadawcy z jego odbiorcą, ponieważ umożliwia obsłużenieżądaniawięcej niż jednemu obiektowi. Łączy w łańcuch obiekty odbiorcze i przekazuje między nimi żądanie do momenu obsłużenia go.

(9)

Łańcuch zobowiązań

Handler

handleRequest()

ConcreteHandler1

handleRequest()

ConcreteHandler2

handleRequest()

Client

successor

Wzorce operacyjne 9 / 120

(10)

abstract class PurchasePower { //Handler protected static final double BASE = 500;

protected PurchasePower successor;

abstract protected double getAllowable();

abstract protected String getRole();

public void setSuccessor(PurchasePower successor) { this.successor = successor;

}

public void processRequest(PurchaseRequest request) { if (request.getAmount() < this.getAllowable()) {

System.out.println(this.getRole() + " will approve

$" + request.getAmount());

} else if (successor != null) { successor.processRequest(request);

} } }

(11)

Łańcuch zobowiązań

class ManagerPPower extends PurchasePower { //

ConcreteHandler1

protected int getAllowable(){

return BASE*10;

}

protected String getRole(){

return "Manager";

} }

class DirectorPPower extends PurchasePower { protected int getAllowable(){

return BASE*20;

}

protected String getRole(){

return "Director";

(12)

class VicePresidentPPower extends PurchasePower { protected int getAllowable(){

return BASE*40;

}

protected String getRole(){

return "Vice President";

} }

class PresidentPPower extends PurchasePower { protected int getAllowable(){

return BASE*60;

}

protected String getRole(){

return "President";

} }

(13)

Łańcuch zobowiązań

class PurchaseRequest { private double amount;

private String purpose;

public PurchaseRequest(double amount, String purpose) { this.amount = amount;

this.purpose = purpose;}

public double getAmount() { return amount;}

public void setAmount(double amt) { amount = amt;

}

public String getPurpose() { return purpose;

}

public void setPurpose(String reason) { purpose = reason;

(14)

class CheckAuthority { // Client

public static void main(String[] args) {

ManagerPPower manager = new ManagerPPower();

DirectorPPower director = new DirectorPPower();

VicePresidentPPower vp = new VicePresidentPPower();

PresidentPPower president = new PresidentPPower();

manager.setSuccessor(director);

director.setSuccessor(vp);

vp.setSuccessor(president);

(15)

Łańcuch zobowiązań

try {

while (true) {

System.out.println("Enter the amount to check who should approve your expenditure.");

System.out.print(">");

double d = Double.parseDouble(new BufferedReader(new

InputStreamReader(System.in)).readLine());

manager.processRequest(new PurchaseRequest(d,

"General"));

}

} catch(Exception e) { System.exit(1);

} }

(16)

Łańcuch zobowiązań może być stosowany ze wzorcemKompozyt.

Wtedy obiekt nadrzędny komponentu może pełnić funkcję jego następnika.

(17)

Polecenie (ang. command )

Kapsułkujeżądanie w formie obiektu. Umożliwia to parametryzację klienta przy użyciu różnych żądań oraz umieszczanie żądań w kolejkach i dziennikach, a także zapewnia obsługę cofania operacji.

(18)

Client

Receiver

action()

Invoker Command

execute()

ConcreteCommand

state execute() receiver

receiver.action();

Rysunek 3:Źródło: własne

Wzorce operacyjne 18 / 120

(19)

Polecenie

import java.util.List;

import java.util.ArrayList;

/** The Command interface */

public interface Command { void execute();

}

/** The Invoker class */

public class Switch {

private List<Command> history = new ArrayList<Command>();

public void storeAndExecute(Command cmd) { this.history.add(cmd); // optional

cmd.execute();

}

(20)

/** The Receiver class */

public class Light { public void turnOn() {

System.out.println("The light is on");

}

public void turnOff() {

System.out.println("The light is off");

} }

(21)

Polecenie

/** The Command for turning on the light */

public class FlipUpCommand implements Command { //

ConcreteCommand

private Light theLight; //receiver public FlipUpCommand(Light light) {

this.theLight = light;

}

@Override

public void execute() { theLight.turnOn();

} }

(22)

/** The Command for turning off the light */

public class FlipDownCommand implements Command { private Light theLight;

public FlipDownCommand(Light light) { this.theLight = light;

}

@Override

public void execute() { theLight.turnOff();

} }

(23)

Polecenie

/* The test class or client */

public class PressSwitch {

public static void main(String[] args){

// Check number of arguments if (args.length != 1) {

System.err.println("Argument \"ON\" or \"OFF\" is required.");

System.exit(-1);

}

Light lamp = new Light(); // Receiver

Command switchUp = new FlipUpCommand(lamp);

Command switchDown = new FlipDownCommand(lamp);

(24)

Switch mySwitch = new Switch();

switch(args[0]) { case "ON":

mySwitch.storeAndExecute(switchUp);

break;

case "OFF":

mySwitch.storeAndExecute(switchDown);

break;

default:

System.err.println("Argument \"ON\" or \"OFF\" is required.");

System.exit(-1);

} } }

(25)

Polecenie

do implementacji Polecenia można użyć wzorca Kompozyt

Polecenie, które jest kopiowane przed umieszczeniem w historii, działa jak Prototyp

(26)

określa reprezentację gramatyki języka oraz interpreter, który

wykorzystuje tę reprezentację do interpretowania zdań z danego języka

(27)

Interpreter

TerminalExpression

interpret(Context)

Client

Context

AbstractExpression

interpret(Context)

NonterminalExpression

interpret(Context)

Wzorce operacyjne 27 / 120

(28)

import java.util.Map

interface Expression { // AbstractExpression

public int interpret(Map<String,Expression> variables);

}

class Number implements Expression { // TerminalExpression private int number;

public Number(int number) { this.number = number;

}

public int interpret(Map<String,Expression> variables) { return number;

} }

(29)

Interpreter

class Plus implements Expression { // NonterminalExpression Expression leftOperand;

Expression rightOperand;

public Plus(Expression left, Expression right) { leftOperand = left;

rightOperand = right;

}

public int interpret(Map<String,Expression> variables) { return leftOperand.interpret(variables) +

rightOperand.interpret(variables);

} }

(30)

class Minus implements Expression { Expression leftOperand;

Expression rightOperand;

public Minus(Expression left, Expression right) { leftOperand = left;

rightOperand = right;

}

public int interpret(Map<String,Expression> variables) { return leftOperand.interpret(variables) -

rightOperand.interpret(variables);

} }

(31)

Interpreter

class Variable implements Expression { private String name;

public Variable(String name) { this.name = name; } public int interpret(Map<String,Expression> variables) {

if(null==variables.get(name)) return 0; //Either return new Number(0).

return variables.get(name).interpret(variables);

} }

(32)

import java.util.Map;

import java.util.Stack;

class Evaluator implements Expression { private Expression syntaxTree;

public Evaluator(String expression) { Stack<Expression> expressionStack = new Stack<Expression>();

for (String token : expression.split(" ")) { if (token.equals("+")) {

Expression subExpression = new

Plus(expressionStack.pop(), expressionStack.pop());

expressionStack.push( subExpression );

} else if (token.equals("-")) {

// it’s necessary remove first the right operand from the stack

Expression right = expressionStack.pop();

(33)

Interpreter

// ..and after the left one

Expression left = expressionStack.pop();

Expression subExpression = new Minus(left, right);

expressionStack.push( subExpression );

} else

expressionStack.push( new Variable(token) );

}

syntaxTree = expressionStack.pop();

}

public int interpret(Map<String,Expression> context) { return syntaxTree.interpret(context);

} }

(34)

import java.util.Map;

import java.util.HashMap;

public class InterpreterExample { // Client public static void main(String[] args) {

String expression = "w x z - +";

Evaluator sentence = new Evaluator(expression);

Map<String,Expression> variables = new HashMap<String,Expression>();

variables.put("w", new Number(5));

variables.put("x", new Number(10));

variables.put("z", new Number(42));

int result = sentence.interpret(variables);

System.out.println(result);

} }

(35)

Iterator

zapewnia sekwencyjny dostęp do elementówobiektu złożonego bez ujawniania jego wewnętrznej reprezentacji.

(36)

Aggregate

createIterator()

ConcreteAggregate

createIterator()

Iterator

first() next() isDone() currentItem()

ConcreteIterator

return new ConcreteIterator(this)

Rysunek 5:Źródło: własne

Wzorce operacyjne 36 / 120

(37)

Iterator

public interface Iterator<E> { // java.util.Iterator boolean hasNext();

E next();

default void remove() {

throw new UnsupportedOperationException("remove");

}

default void forEachRemaining(Consumer<? super E>

action) {

Objects.requireNonNull(action);

while (hasNext())

action.accept(next());

} }

(38)

private class Itr implements Iterator<E> { // class in java.util.AbstractList ConcreteIterator

/**

* Index of element to be returned by subsequent call to next.

*/

int cursor = 0;

/**

* Index of element returned by most recent call to next or

* previous. Reset to -1 if this element is deleted by a call

* to remove.

*/

int lastRet = -1;

(39)

Iterator

/**

* The modCount value that the iterator believes that the backing

* List should have. If this expectation is violated, the iterator

* has detected concurrent modification.

*/

int expectedModCount = modCount;

public boolean hasNext() { return cursor != size();

}

(40)

public E next() {

checkForComodification();

try {

int i = cursor;

E next = get(i);

lastRet = i;

cursor = i + 1;

return next;

} catch (IndexOutOfBoundsException e) { checkForComodification();

throw new NoSuchElementException();

} }

(41)

Iterator

public void remove() { if (lastRet < 0)

throw new IllegalStateException();

checkForComodification();

try {

AbstractList.this.remove(lastRet);

if (lastRet < cursor) cursor--;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException e) {

throw new ConcurrentModificationException();

} }

final void checkForComodification() { if (modCount != expectedModCount)

throw new ConcurrentModificationException();

Wzorce operacyjne 41 / 120

(42)

w interfejsie List // Aggregate

ListIterator<E> listIterator();

w AbstractList // ConcreteAggregate

public ListIterator<E> listIterator() { return listIterator(0);

}

public ListIterator<E> listIterator(final int index) { rangeCheckForAdd(index);

return new ListItr(index);

}

(43)

Iterator

można użyć tego wzorca do przechodzenia po zawartości kompozytów

(44)

określa obiekt kapsułkujący informacje o interakcji między obiektami z danego zbioru. Wzorzec ten pomaga zapewnić luźne powiązanie, ponieważ zapobiega bezpośredniemu odwoływaniu się obiektów do siebie i umożliwia niezależne modyfikowanie interakcji między nimi.

(45)

Mediator

Mediator Colleague

ConcreteMediator

ConreteColleague1

ConreteColleague2

mediator

Wzorce operacyjne 45 / 120

(46)

import java.awt.Font;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

interface Command { // Colleague void execute();

}

(47)

Mediator

interface Mediator { void book();

void view();

void search();

void registerView(BtnView v);

void registerSearch(BtnSearch s);

void registerBook(BtnBook b);

void registerDisplay(LblDisplay d);

}

(48)

//Concrete mediator

class ParticipantMediator implements Mediator { BtnView btnView;

BtnSearch btnSearch;

BtnBook btnBook;

LblDisplay show;

//....

public void registerView(BtnView v) { btnView = v;}

public void registerSearch(BtnSearch s) { btnSearch = s;}

public void registerBook(BtnBook b) { btnBook = b;

}

public void registerDisplay(LblDisplay d) { show = d;

}

(49)

Mediator

public void book() {

btnBook.setEnabled(false);

btnView.setEnabled(true);

btnSearch.setEnabled(true);

show.setText("booking...");

}

public void view() {

btnView.setEnabled(false);

btnSearch.setEnabled(true);

btnBook.setEnabled(true);

show.setText("viewing...");

}

public void search() {

btnSearch.setEnabled(false);

btnView.setEnabled(true);

btnBook.setEnabled(true);

show.setText("searching...");

Wzorce operacyjne 49 / 120

(50)

//A concrete colleague

class BtnView extends JButton implements Command { Mediator med;

BtnView(ActionListener al, Mediator m) { super("View");

addActionListener(al);

med = m;

med.registerView(this);

}

public void execute() { med.view();

} }

(51)

Mediator

//A concrete colleague

class BtnSearch extends JButton implements Command { Mediator med;

BtnSearch(ActionListener al, Mediator m) { super("Search");

addActionListener(al);

med = m;

med.registerSearch(this);

}

public void execute() { med.search();

} }

(52)

//A concrete colleague

class BtnBook extends JButton implements Command { Mediator med;

BtnBook(ActionListener al, Mediator m) { super("Book");

addActionListener(al);

med = m;

med.registerBook(this);

}

public void execute() { med.book();

} }

(53)

Mediator

class LblDisplay extends JLabel { Mediator med;

LblDisplay(Mediator m) { super("Just start...");

med = m;

med.registerDisplay(this);

setFont(new Font("Arial", Font.BOLD, 24));

} }

(54)

class MediatorDemo extends JFrame implements ActionListener {

Mediator med = new ParticipantMediator();

MediatorDemo() {

JPanel p = new JPanel();

p.add(new BtnView(this, med));

p.add(new BtnBook(this, med));

p.add(new BtnSearch(this, med));

getContentPane().add(new LblDisplay(med), "North");

getContentPane().add(p, "South");

setSize(400, 200);

setVisible(true);}

public void actionPerformed(ActionEvent ae) { Command comd = (Command) ae.getSource();

comd.execute();}

public static void main(String[] args) { new MediatorDemo();}

}

Wzorce operacyjne 54 / 120

(55)

Mediator

mediator vsfasada: fasada to abstrakcyjne ujęcie interfejsu, fasada nie definiuje nowych funkcji, a klasy podsystemu nie wiedzą o jej istnieniu, mediator to wyabstrahowanie dowolnej komunikacji między obiektami

(56)

Bez naruszania kapsułkowania rejestruje i zapisujew zewnętrznej jednostce wewnętrzny stan obiektu, co umożliwia późniejsze przywrócenie obiektu według zapamiętanego stanu.

(57)

Pamiątka

Rysunek 7:Źródło: wikipedia

(58)

import java.util.List;

import java.util.ArrayList;

class Originator { private String state;

// The class could also contain additional data that is not part of the

// state saved in the memento..

public void set(String state) {

System.out.println("Originator: Setting state to " + state);

this.state = state;

}

public Memento saveToMemento() {

System.out.println("Originator: Saving to Memento.");

return new Memento(this.state);

}

(59)

Pamiątka

public void restoreFromMemento(Memento memento) { this.state = memento.getSavedState();

System.out.println("Originator: State after restoring from Memento: " + state);

}

public static class Memento { private final String state;

public Memento(String stateToSave) { state = stateToSave;

}

public String getSavedState() { return state;

} } }

(60)

class Caretaker {

public static void main(String[] args) { List<Originator.Memento> savedStates = new ArrayList<Originator.Memento>();

Originator originator = new Originator();

originator.set("State1");

originator.set("State2");

savedStates.add(originator.saveToMemento());

originator.set("State3");

// We can request multiple mementos, and choose which one to roll back to.

savedStates.add(originator.saveToMemento());

originator.set("State4");

originator.restoreFromMemento(savedStates.get(1));

} }

(61)

Pamiątka

Pamiątka umożliwia zachowanie stanu potrzebnegoPoleceniu do cofnięcia efektów jego wykonania.

(62)

Określa zależność jeden do wielu między obiektami. Kiedy zmieni się stan jednego z obiektów, wszystkie obiekty zależne od niego są o tym automatycznie powiadamiane i aktualizowane.

inne nazwy publikuj-subskrybuj (ang. publish-subscribe)

(63)

Obserwator

Subject Attach(Observer) Detach(Observer) Notify()

ConcreteSubject subjectState GetState() SetState()

Observer Update()

ConcreteObserver observerState Update() observers

subject for every o in observers { o->Update()

}

return subjectState

observerState = subject->GetState()

Wzorce operacyjne 63 / 120

(64)

public interface Observer { // java.util.Observer void update(Observable o, Object arg);

}

public class Observable { // Subject private boolean changed = false;

private Vector<Observer> obs; // observers public Observable() {

obs = new Vector<>();

}

public synchronized void addObserver(Observer o) { if (o == null)

throw new NullPointerException();

if (!obs.contains(o)) { obs.addElement(o);

} }

(65)

Obserwator

public synchronized void deleteObserver(Observer o) { obs.removeElement(o);

}

public void notifyObservers() { // notify notifyObservers(null);

}

public void notifyObservers(Object arg) { Object[] arrLocal;

synchronized (this) { if (!changed)

return;

arrLocal = obs.toArray();

clearChanged();

}

for (int i = arrLocal.length-1; i>=0; i--)

(66)

public synchronized void deleteObservers() { obs.removeAllElements();

}

protected synchronized void setChanged() { changed = true;

}

protected synchronized void clearChanged() { changed = false;

}

public synchronized boolean hasChanged() { return changed;

}

public synchronized int countObservers() { return obs.size();

}

(67)

Obserwator

import java.util.Observable;

import java.util.Scanner;

class EventSource extends Observable implements Runnable { // ConcreteSubject

public void run() { while (true) {

String response = new Scanner(System.in).next();

setChanged();

notifyObservers(response);

} } }

(68)

import java.util.Observable;

import static java.lang.System.out;

class MyApp {

public static void main(String[] args) { out.println("Enter Text >");

EventSource eventSource = new EventSource();

eventSource.addObserver( (Observable obj, Object arg) -> {

out.println("\nReceived response: " + arg);

});

new Thread(eventSource).start();

} }

(69)

Obserwator

można utworzyć dodatkową klasę między podmiotami, a obserwatorami, o nazwie Manager do której można zastosować wzorzec Singleton. Klasa ta działa jakmediatormiędzy podmiotami i obserwatorami. Klasa Manager może mieć mapę przyporządkowania obserwatorów do podmiotów i implementować złożoną semantykę aktualizacji

(70)

Umożliwia obiektowi modyfikację zachowania w wyniku zmiany wewnętrznego stanu. Wygląda to tak, jakby obiekt zmienił klasę.

(71)

Stan

Context +request()

state.handle()

State +handle()

ConcreteStateA +handle()

ConcreteStateB +handle() Rysunek 9:Źródło: wikipedia

(72)

interface Statelike { // State

void writeName(StateContext context, String name); //

handle }

class StateLowerCase implements Statelike { //

ConcreteState

@Override

public void writeName(final StateContext context, final String name) {

System.out.println(name.toLowerCase());

context.setState(new StateMultipleUpperCase());

} }

(73)

Stan

class StateMultipleUpperCase implements Statelike { /** Counter local to this state */

private int count = 0;

@Override

public void writeName(final StateContext context, final String name) {

System.out.println(name.toUpperCase());

/* Change state after StateMultipleUpperCase’s writeName() gets invoked twice */

if(++count > 1) {

context.setState(new StateLowerCase());

} } }

(74)

class StateContext { // Context private Statelike myState;

StateContext() {

setState(new StateLowerCase());

} /**

* Setter method for the state.

* Normally only called by classes implementing the State interface.

* @param newState the new state of this context

*/

void setState(final Statelike newState) { myState = newState;

}

public void writeName(final String name) { myState.writeName(this, name);

} }

Wzorce operacyjne 74 / 120

(75)

Stan

public class DemoOfClientState {

public static void main(String[] args) { final StateContext sc = new StateContext();

sc.writeName("Monday");

sc.writeName("Tuesday");

sc.writeName("Wednesday");

sc.writeName("Thursday");

sc.writeName("Friday");

sc.writeName("Saturday");

sc.writeName("Sunday");

} }

(76)

obiekty State mogą być singletonami

wzorzec Pyłekokreśla kiedy i jak można współużytkować obiekty State

(77)

Strategia (ang. strategy )

Określa rodzinę algorytmów, kapsułkuje każdy z nich i umożliwia ich zamienne stosowanie. Wzorzec ten pozwala zmieniać algorytmy niezależnie od korzystających z nich klientów.

(78)

Context

ContextInterface()

Strategy

AlgorithmInterface()

ConcreteStrategyA

AlgorithmInterface()

ConcreteStrategyB

AlgorithmInterface()

ConcreteStrategyC

AlgorithmInterface() strategy

Rysunek 10:Źródło: własne

Wzorce operacyjne 78 / 120

(79)

Strategia

interface BillingStrategy { // Strategy

public double getActPrice(double rawPrice);

}

// Normal billing strategy (unchanged price) class NormalStrategy implements BillingStrategy {

@Override

public double getActPrice(double rawPrice) { return rawPrice;

} }

// Strategy for Happy hour (50% discount)

class HappyHourStrategy implements BillingStrategy {

@Override

public double getActPrice(double rawPrice) { return rawPrice*0.5;

(80)

class Customer { // Context private List<Double> drinks;

private BillingStrategy strategy;

public Customer(BillingStrategy strategy) { this.drinks = new ArrayList<Double>();

this.strategy = strategy;

}

public void add(double price, int quantity) {

drinks.add(strategy.getActPrice(price * quantity));

}

// Payment of bill

public void printBill() { double sum = 0;

for (Double i : drinks) { sum += i;

}

System.out.println("Total due: " + sum);

drinks.clear();

}

Wzorce operacyjne 80 / 120

(81)

Strategia

// Set Strategy

public void setStrategy(BillingStrategy strategy) { this.strategy = strategy;

} }

public class StrategyPatternWiki {

public static void main(String[] args) {

Customer a = new Customer(new NormalStrategy());

// Normal billing a.add(1.0, 1);

// Start Happy Hour

a.setStrategy(new HappyHourStrategy());

a.add(1.0, 2);

// New Customer

Customer b = new Customer(new HappyHourStrategy());

(82)

// The Customer pays a.printBill();

// End Happy Hour

b.setStrategy(new NormalStrategy());

b.add(1.3, 2);

b.add(2.5, 1);

b.printBill();

} }

(83)

Strategia

obiekty Strategy mogą być tworzone jakopyłki

strategia vsdekorator: dekorator umożliwia zmianę skórki obiektu, strategia modyfikuje mechanizmy

(84)

most należy do wzorców strukturalnych, a strategia do wzorców operacyjnych, strategia operuje na algorytmach

most posiada klasę RefinedAbstraction, oraz klasę abstrakcyjną Abstraction, natomiast strategia posiada klasę Context, która nie jest abstrakcyjna

(85)

Metoda szablonowa (ang. template method )

Określa szkielet algorytmu i pozostawia doprecyzowanie niektórych jego kroków podklasom. Umożliwia modyfikację niektórych etapów algorytmu w podklasach bez zmiany jego struktury.

(86)

AbstractClass

templateMethod() primitiveOperation1() primitiveOperation2()

ConcreteClass

primitiveOperation1() primitiveOperation2()

...

primitiveOperation1() ...

primitiveOperation2() ...

Rysunek 11:Źródło: własne

Wzorce operacyjne 86 / 120

(87)

Metoda szablonowa

/**

* An abstract class that is common to several games in

* which players play against the others, but only one is

* playing at a given time.

*/

abstract class Game { // AbstractClass

/* Hook methods. Concrete implementation may differ in each subclass*/

protected int playersCount;

abstract void initializeGame();

abstract void makePlay(int player); //

primitiveOperation1

abstract boolean endOfGame();

abstract void printWinner(); // primitiveOperation2

(88)

/* A template method : */

public final void playOneGame(int playersCount) { this.playersCount = playersCount;

initializeGame();

int j = 0;

while (!endOfGame()) { makePlay(j);

j = (j + 1) % playersCount;

}

printWinner();

} }

(89)

Metoda szablonowa

//Now we can extend this class in order //to implement actual games:

class Monopoly extends Game {

/* Implementation of necessary concrete methods */

void initializeGame() { // Initialize players // Initialize money }

void makePlay(int player) { // Process one turn of player }

boolean endOfGame() {

// Return true if game is over // according to Monopoly rules }

void printWinner() { // Display who won }

Wzorce operacyjne 89 / 120

(90)

class Chess extends Game {

/* Implementation of necessary concrete methods */

void initializeGame() { // Initialize players

// Put the pieces on the board }

void makePlay(int player) {

// Process a turn for the player }

boolean endOfGame() {

// Return true if in Checkmate or // Stalemate has been reached }

void printWinner() {

// Display the winning player }

/* Specific declarations for the chess game. */

}

Wzorce operacyjne 90 / 120

(91)

Metoda szablonowa

w metodach szablonowych fragmenty algorytmu modyfikowane są przez dziedziczenie, a wstrategiiza pomocą delegowania zmieniany jestcały algorytm

metody wytwórcze mogą być wywoływane przez metody szablonowe

(92)

Reprezentuje operację wykonywaną na elementach struktury obiektów. Wzorzec ten umożliwia zdefiniowanie nowej operacjibez zmieniania klas elementów, na których działa.

(93)

Odwiedzający

Element accept(Visitor) ObjectStructure

Visitor

visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB)

ConcreteVisitor1 visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB)

ConcreteElementA accept(Visitor v) operationA()

ConcreteVisitor2 visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB)

ConcreteElementB accept(Visitor v) operationB()

v->visitConcreteElementA(this) v->visitConcreteElementB(this)

Wzorce operacyjne 93 / 120

(94)

interface ICarElementVisitor { // Visitor void visit(Wheel wheel);

void visit(Engine engine);

void visit(Body body);

void visit(Car car);

}

interface ICarElement { // Element

void accept(ICarElementVisitor visitor);

}

class Wheel implements ICarElement { // ConcreteElementA private String name;

public Wheel(String name) { this.name = name;

}

public String getName() { return this.name;

}

(95)

Odwiedzający

public void accept(ICarElementVisitor visitor) { visitor.visit(this);

} }

class Engine implements ICarElement {

public void accept(ICarElementVisitor visitor) { visitor.visit(this);

} }

class Body implements ICarElement {

public void accept(ICarElementVisitor visitor) { visitor.visit(this);

} }

(96)

class Car implements ICarElement { ICarElement[] elements;

public Car() {

this.elements = new ICarElement[] { new Wheel("front left"),

new Wheel("front right"), new Wheel("back left") , new Wheel("back right"), new Body(), new Engine() };

}

public void accept(ICarElementVisitor visitor) { for(ICarElement elem : elements) {

elem.accept(visitor);

}

visitor.visit(this);

} }

(97)

Odwiedzający

class CarElementPrintVisitor implements ICarElementVisitor {

public void visit(Wheel wheel) {

System.out.println("Visiting " + wheel.getName() + "

wheel");

}

public void visit(Engine engine) {

System.out.println("Visiting engine");

}

public void visit(Body body) {

System.out.println("Visiting body");

}

public void visit(Car car) {

System.out.println("Visiting car");

}

(98)

class CarElementDoVisitor implements ICarElementVisitor { public void visit(Wheel wheel) {

System.out.println("Kicking my " + wheel.getName() + "

wheel");

}

public void visit(Engine engine) {

System.out.println("Starting my engine");

}

public void visit(Body body) {

System.out.println("Moving my body");

}

public void visit(Car car) {

System.out.println("Starting my car");

} }

(99)

Odwiedzający

public class VisitorDemo {

public static void main(String[] args) { ICarElement car = new Car();

car.accept(new CarElementPrintVisitor());

car.accept(new CarElementDoVisitor());

} }

(100)

Chcemy miec poszczególne ConcreteElement w osobnych projektach.

Problem jest taki, że projekty te muszą być zależne od projektu zawierającego interfejs Element, zaś projekt, który zawiera interfejs Element, musi być zależny od interfejsu Visitor, który jest zależny od poszczególnych ConcreteElement, otrzymujemy zależność cykliczną projektów.

Rozwiązanie: dodatkowy interfejs SolverVisitor jest w projekcie SVM Core, SolverSVMTesterVisitor w projekcie SVM Tester, a poszczególni odwiedzający jak np. SolverDetailLoggerVisitor mogą być też w SVM Tester, element Solver w SVM Core, a klasy dziedziczące we własnych projektach. W projekcie SVM Core nie mamy wiedzy na temat klas dziedziczących po klasie Solver.

public interface SolverVisitor {

void visit(Solver solver);

}

(101)

Odwiedzający

public interface SolverSVMTesterVisitor extends SolverVisitor

{

void visit(AdvancedSolverExternalSVM advancedSolverExternalSVM);

void visit(AdvancedSolverL2NormSVC advancedSolverL2NormSVC);

void visit(AdvancedSolverSVC advancedSolverSVC);

void visit(AdvancedSolverDeltaSVR advancedSolverDeltaSVR);

void visit(AdvancedSolverDistributionFinder advancedSolverDistributionFinder);

void visit(AdvancedSolverDoubleSVC advancedSolverDoubleSVC);

void visit(SolverSVCCurveFitting solverSVCCurveFitting);

(102)

public class Bar {

public void visit(Foo foo) {

System.out.println("Visiting Foo");

}

public void visit(SubFoo foo) {

System.out.println("Visiting SubFoo");

} }

public class Foo {}

public class SubFoo extends Foo {}

public class Main {

public static void main(String[] args) { Bar bar = new Bar();

Foo foo = new SubFoo();

bar.visit(foo);

} }

(103)

Odwiedzający

public class SolverDetailLoggerVisitor implements SolverSVMTesterVisitor

{

private String detailLog;

public SolverDetailLoggerVisitor() {}

public String getDetailLog() {

return detailLog;}

@Override

public void visit(Solver solver) {

ReflectionUtils.invokeCurrentMethod(this, solver);}

@Override

public void visit(AdvancedSolverExternalSVM advancedSolverExternalSVM)

(104)

public static Object invokeCurrentMethod(Object object, Object... parameters)

{

try {

final StackTraceElement[] ste =

Thread.currentThread().getStackTrace();

String methodName = ste[2].getMethodName();

Class<?>[] parametersClasses = new Class[parameters.length];

for (int i = 0; i < parameters.length; i++) {

parametersClasses[i] = parameters[i].getClass();

}

Method m = object.getClass().getMethod(methodName, parametersClasses);

Object o = m.invoke(object, parameters);

return o;

} catch (IllegalAccessException |

IllegalArgumentException | InvocationTargetException | NoSuchMethodException e)

{

logger.error(Constants.EMPTY_STRING, e);

}

assert false;

return null;

}

Wzorce operacyjne 104 / 120

(105)

Odwiedzający

public interface Solver {

void solve();

Curve getCurve();

void acceptVisitor(SolverVisitor solverVisitor);

}

public class SolverBFDF extends SolverWithKernel {

@Override

public void acceptVisitor(SolverVisitor solverVisitor) {

solverVisitor.visit(this);

} ...

(106)

SolverDetailLoggerVisitor solverDetailLoggerVisitor = new SolverDetailLoggerVisitor();

solverParameters.getSvmSolver().acceptVisitor(solverDetailLoggerVisitor);

stringBuffer.append(solverDetailLoggerVisitor.getDetailLog());

można również pozbyć się klasy SolverSVMTesterVisitor, wtedy nie musimy dodawać do niej metody po dodaniu nowego typu Solvera

(107)

Odwiedzający

wzorzec ten może być wykorzystany do przeprowadzeniainterpretacji wzorzec ten może być wykorzystany do zastosowania operacji dla struktury obiektów we wzorcu Kompozyt

odwiedzający vs kompozyt: we wzorcu Odwiedzający jest jedna lokalizacja dla operacji, w kompozycie są one rozproszone

(108)

reguły biznesowe mogą być łączone ponownie za pomocą logiki boolean

(109)

Specyfikacja

(110)

public interface ISpecification {

boolean isSatisfiedBy(Object candidate);

ISpecification and(ISpecification other);

ISpecification andNot(ISpecification other);

ISpecification or(ISpecification other);

ISpecification orNot(ISpecification other);

ISpecification not();

}

(111)

Specyfikacja

public abstract class CompositeSpecification implements ISpecification

{

public abstract boolean isSatisfiedBy(Object candidate);

public ISpecification and(ISpecification other) {

return new AndSpecification(this, other); } public ISpecification andNot(ISpecification other) {

return new AndNotSpecification(this, other); } public ISpecification or(ISpecification other) {

return new OrSpecification(this, other); }

(112)

public ISpecification orNot(ISpecification other) {

return new OrNotSpecification(this, other); } public ISpecification not()

{

return new NotSpecification(this); } }

(113)

Specyfikacja

public class AndSpecification extends CompositeSpecification

{

private ISpecification leftCondition;

private ISpecification rightCondition;

public AndSpecification(ISpecification left, ISpecification right)

{

leftCondition = left;

rightCondition = right;

}

public boolean isSatisfiedBy(Object candidate) {

return leftCondition.isSatisfiedBy(candidate) &&

rightCondition.isSatisfiedBy(candidate);

(114)

public class AndNotSpecification extends CompositeSpecification

{

private ISpecification leftCondition;

private ISpecification rightCondition;

public AndSpecification(ISpecification left, ISpecification right)

{

leftCondition = left;

rightCondition = right;

}

public boolean isSatisfiedBy(Object candidate) {

return leftCondition.isSatisfiedBy(candidate) &&

rightCondition.isSatisfiedBy(candidate) != true;

} }

(115)

Specyfikacja

public class OrSpecification extends CompositeSpecification {

private ISpecification leftCondition;

private ISpecification rightCondition;

public OrSpecification(ISpecification left, ISpecification right)

{

leftCondition = left;

rightCondition = right;

}

public boolean isSatisfiedBy(Object candidate) {

return leftCondition.isSatisfiedBy(candidate) ||

rightCondition.isSatisfiedBy(candidate);

}

(116)

public class OrNotSpecification extends CompositeSpecification

{

private ISpecification leftCondition;

private ISpecification rightCondition;

public OrSpecification(ISpecification left, ISpecification right)

{

leftCondition = left;

rightCondition = right;

}

public boolean isSatisfiedBy(Object candidate) {

return leftCondition.isSatisfiedBy(candidate) ||

rightCondition.isSatisfiedBy(candidate) != true;

} }

(117)

Specyfikacja

public class NotSpecification extends CompositeSpecification

{

private ISpecification wrapped;

public NotSpecification(ISpecification x) {

wrapped = x;

}

public boolean isSatisfiedBy(Object candidate) {

return !wrapped.isSatisfiedBy(candidate);

} }

(118)

OverDueSpecification overDue = new OverDueSpecification();

NoticeSentSpecification noticeSent = new NoticeSentSpecification();

InCollectionSpecification inCollection = new InCollectionSpecification();

// example of specification pattern logic chaining ISpecification<Invoice> sendToCollection =

overDue.and(noticeSent).and(inCollection.not());

invoiceCollection = service.getInvoices();

for (Invoice currentInvoice : invoiceCollection) {

if (sendToCollection.isSatisfiedBy(currentInvoice)) { currentInvoice.sendToCollection();

} }

(119)

Bez wzorca specyfikacja

invoiceCollection = service.getInvoices();

for (Invoice currentInvoice : invoiceCollection) { currentInvoice.sendToCollectionIfNecessary();

}

//.. in the Invoice partial class:

public boolean shouldSendToCollection() { return overDue

&& noticeSent == false && inCollection == false; } public void sendToCollectionIfNecessary()

{

//Guard condition - with each of those new properties if (!shouldSendToCollection()) return;

this.sendToCollection();

}

(120)

blackboard– łączenie różnych źródeł danych

pusty obiekt, ang. null object – unikanie referencji null za pomocą dostarczania domyślnego obiektu z działaniami nie wykonującymi żadnych operacji

servant– definicja wspólnej funkcjonalności dla grupy klas bez definiowania tej funkcjonalności w każdej z nich

Cytaty

Powiązane dokumenty

In the case of inwards flow created by the active particle, passive particles organise into a hexagonal structure around the immobile active particle under green light illumination

− różnicowania roli Unii Europejskiej. Z jednej strony utrzymuje się wiara w pragmatyczne znaczenie dziś i jutro platformy wspólnotowych wartości, z drugiej strony

Przeprowadzenie analizy podstawowych zasad zarządzania wartością, jakością kompleksową i normatywną może udzielić odpowiedzi na pytanie o koncepcyjną zgod- ność

Miesięczniki: Ateneum (Warszawa) Biblioteka warszawska Chimera (Warszawa) Krytyka (Kraków) Książka (Warszawa) Muzeum (Lwów).. Pogląd na świat (Kraków) Promień

Rzeuskiej z tytułu należy do zakresu zagadnień lite­ raturoznawczych, w istocie jednak bardzo znaczna jego część po­ święcona jest dowodzeniu, że gwara

nie ma tu miejsca na jej szczegółowe omówienie 6 , wystarczy jednak powiedzieć, że teza o otwartości tekstu i rozumienia go jako generatora sensu doprowadza w skrajnej

Całkowicie nie można zgodzić się także z twierdzeniem, że propaganda lansowała wówczas tezę, jakoby „Opanowana przez syjonistów policja polityczna zajmowała się

Badaczy może ona mobilizować do podejmowania analogicznych zagadnień odnoszących się do innych diecezji (archidiakonatów, dekanatów, parafi i), miłośnikom historii