Behavioral Patterns
-
Behavioral Patterns:
- Characterize the ways in which classes or objects interact and distribute responsibility.
- Concerned with algorithms and the assignment of responsibilities between objects
- Describes object / class patterns as well as the resulting communication patterns between them
-
Behavioral Patterns
- Some Examples:
- Observer
- Strategy
- Template
- Command
-
Observer Pattern
-
Observer Pattern
Concepts
- One to Many Observers
- Decoupled
- Event Handling
- Pub/Sub
- M-V-C
-
Design
- Subject - that needs to be observed
- Interface or Abstract class from which concrete implementations derive
- Observers will register with the Subject
-
- Observer - is interface base with concrete implementations
- Observable - interface base with concrete implementation
- Add/Remove observer from observable
- Notify observer on state change of observable
-
Observable
- Responsible for notifying registered observers of state-change
public interface Observable<T extends Observer> {
void register(T observer);
void unregister(T observer);
void notify()
List<Observer> getAllObservers();
}
-
What is an Observer?
- Responsible for being updated upon Observable state-change
public interface Observer { void update(); }
leading to:
public abstract class AbstractObserver implements Observer {
protected Observed observed;
}
- ###Subject of Observation:
import java.util.ArrayList;
import java.util.List;
public class Observed {
private List<Observer> observers = new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void gather(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
- ###Extend the Observer
public class StringObserver extends Observer{
public StringObserver(Observed observed){
this.observed = observed;
this.observed.gather(this);
}
@Override
public void update() {
System.out.println( "Observed String State: " + observed.getState() );
}
}
-
Observer Summary
- Decoupled communication
- Built in functionality
- Used with mediator
-
Strategy Pattern
-
Strategy Pattern
Concepts
- Eliminate conditional statements
- Behavior encapsulated in classes
- Difficult to add new strategies
- Client aware of strategies
- Client chooses strategy
-
Strategy Pattern: Design
- Abstract base class
- Concrete class per strategy
- Remove if/else conditionals
- Strategies are independent
-
Strategy Pattern: example
//Collections.sort
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
Collections.sort uses the Strategy pattern. The method expects a strategy to be passed as an argument. This allows the client to decide by which strategy the sort method will execute
-
Strategy Summary
- Externalizes algorithms
- Client knows different Strategies
- Class per Strategy
- Reduces conditional statements
-
Template Pattern
-
Template Pattern
- Create a method of high degree of freedom to define methods of lesser variability
- Degree of freedom is determined by the number of arguments of a method
-
Template Pattern: example
// degree of 1
public static Integer[] getRange(int stop) {
return getRange(0, stop, 1);
}
// degree of 2
public static Integer[] getRange(int start, int stop) {
return getRange(start, stop, 1);
}
// degree of 3; template method
public static Integer[] getRange(int start, int stop, int step) {
List<Integer> list = new ArrayList<>();
for(int i = start; i<stop; i+=step) {
list.add(i);
}
return list.toArray(new Integer[list.size()]);
}
-
Command Pattern
-
Command Pattern
- Command interface
- Decouples “what is done” from “when it is done”
- Concrete commands objects are tasks; i.e. -
UNDO_TASK
-
Command Pattern
You’ll see Command being used often when you need to have multiple undo operations, where a stack of the recently executed commands are maintained. To implement the undo, all you need to do is get the last Command in the stack and execute it’s undo() method.
You’ll also find Command useful for wizards, progress bars, GUI buttons and menu actions, and other transactional behavior.
-
Components of Command Pattern
- Command Interface
- Receiver Class
- Invoker Class
- Client Class
-
Command Interface
public interface MoneyTransaction {
void execute();
}
-
Request Class
public class Account {
private String name = "MYCOOLACCOUNT";
private double balance = 200.00;
public void deposit(double amount) {
balance = balance + amount;
System.out.println("Account [ Name: "+name+",
Amount: " + amount +" ] deposited");
}
public void withdraw(double amount) {
balance = balance - amount;
System.out.println("Account [ Name: "+name+",
Ammount: " + amount +" ] withdrawn");
}
}
-
Concrete Command Class
public class Deposit implements MoneyTransaction {
private Account myAccount;
private double amount;
public Deposit(Account myAccount, double amount) {
this.myAccount = myAccount;
this.amount = amount;
}
public void execute() {
myAccount.deposit(amount);
}
}
-
Concrete Command Class (Continued)
public class Withdrawal implements MoneyTransaction {
private Account myAccount;
private double amount;
public Withdrawal(Account myAccount, double amount) {
this.myAccount = myAccount;
this.amount = amount;
}
public void execute() {
myAccount.withdraw(amount);
}
}
-
Command Invoker Class
import java.util.ArrayList;
import java.util.List;
public class Teller {
private List<MoneyTransaction> transactionList = new ArrayList<MoneyTransaction>();
public void receiveTransaction(MoneyTransaction transaction){
transactionList.add(transaction);
}
public void doTransactions(){
for (MoneyTransaction transaction : transactionList) {
transaction.execute();
}
transactionList.clear();
}
}
-
Now, use the Invoker to take and execute:
public class LetsDoThis {
public static void main(String[] args) {
Account myAccount = new Account();
Deposit stackMoney = new Deposit(myAccount, 200.00);
Withdrawal getMoney = new Withdrawal(myAccount, 100.00);
Teller teller = new Teller();
teller.receiveTransaction(stackMoney);
teller.receiveTransaction(getMoney);
teller.doTransactions();
}
}