the state design pattern idea: internal state == object intent: allow an object to alter its...

25
The State Design Pattern • Idea: internal state == Object • Intent: Allow an object to alter its behaviour when its internal state changes. The object will appear to change its class.

Upload: francis-owens

Post on 01-Jan-2016

221 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

The State Design Pattern

• Idea: internal state == Object• Intent: Allow an object to alter its behaviour

when its internal state changes. The object will appear to change its class.

Page 2: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

State Design Pattern

Open() Close() Acknowledge()

TCPConnection

Open() Close() Acknowledge()

TCPState*

Open() Close() Acknowledge()

TCPEstablished

Open() Close() Acknowledge()

TCPListen

Open() Close() Acknowledge()

TCPClosed

state->Open()

state

Page 3: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

State Pattern• Motivation: some objects may change their behavior at

runtime…– An individual: Prince / Frog

• When kissed, turns into a prince• When cursed, turns into a frog.• If a prince, will go into duel • If a frog, will quack.

– Another individual: Dr. Jekyll / Mr. Hyde• At night: will turn into a Mr. Hyde.• At day: will turn into Dr. Jekyll• If Jekyll: cure patients• If Hyde: murder prostitutes

– A TCP connection: may be open, may be closed.– A Graphic tool: may be a select tool, but may also be a pen

Page 4: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Typical State BehaviorClass C {

field f; method task() {

if (f == someValue)doTaskOneWay;

else if (f == someOtherValue) doTaskInAnotherWay();

} method anotherTask() {

if (f == someValue)doAnotherTaskOneWay;

else if (f == someOtherValue) doAnotherTaskInAnotherWay();

} ….}

Many of the things you do depend

on your state of

mind

Page 5: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

General Technique: Replacing Conditionals by Inheritance

Type Function f() { If (condition) doSomething() else doSomethingElse();}

abstract class A { abstract Type f();}

final class IfCondition { final Type f() { doSomething(); }}

final class ElseCondition { final Type f() { doSomethingElse(); }}

Page 6: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

State Pattern

• Reaps the “if to inheritance” technique• Useful if many methods exhibit different

behavior depending on the same state variables.

Page 7: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Finite Automaton Example

class Automaton {State currentState = State.initial;State state = State.A;

public void op_a(final Automaton context) {state.op_a(context);

}

public void op_b(final Automaton context) {state.op_b(context);

}…

}

A B

C

aa

a

b

b

b

Page 8: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

State as Enumerated TypeClass Automaton {

…enum State {

A {@Override public void op_a(final Automaton context)

{context.state = B;

}

@Override public void op_b(final Automaton context) {

context.state = C;}

},B {…}C {…};

public abstract void op_a(final Automaton context);public abstract void op_b(final Automaton context);

}

Page 9: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

State Structure

Request()

Context

Handle()

State*

state->Handle()

Handle()

ConcreteStateA

state

Handle()

ConcreteStateB

Allow a object to alter its behavior when its internal state changes.

Page 10: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

State Known Users

MousePressed() ProcessKeyboard() Initialize()

DrawingController

HandleMousePress() HandleMouseRelease() GetCurser() Activate()

Tool*currentTool

CreationTool SelectionTool TextTool

• Easy to factor out similar strategies (using inheritance)

Page 11: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Example: AVL Tree• AVL Tree: A balanced binary search tree.

– Main property: in all nodes• Height of left and right subtrees can differ by at most 1

– Node can be either: • Balanced: same height of left- and right- subtrees • Left tipped: left subtree is higher (by 1)• Right tipped: right subtree is higher (by 1)

– Example: tree with only one node.• Node is balanced

• The challenge– Insertion of more nodes, while maintaining the AVL

property.

Page 12: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

An AVL Tree

left

balanced

balanced

balanced

balanced

balanced

balanced

balanced

balanced

rightleft

Page 13: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

AVL Insertion Algorithm1. Insert: as in ordinary binary search tree.2. Balance: traverse the insertion path, bottom up:

– Examine subtree:• If height did not increase, stop traversal.

– Examine parent (height of subtree changed)• Continue:

– Balanced: tip in the appropriate direction.• Stop:

– Right inclined and arriving from left, or– Left inclined and arriving from right:

» Make parent balanced» Stop traversal

• Reorganize and stop:– Right tipping: parent is right inclined and arriving from right,– Left tipping: parent is left inclined and arriving from right:

» Make a local reorganization» Stop

Page 15: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

AVL Tree Implementationpublic class AVLTree<T extends Comparable<T>>

implements Checkable {

Node<T> root;

public AVLTree() {root = null;

}

public boolean isEmpty() {return root == null;

}

public void clear() {root = null;

}…

}

Page 16: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Inorder Traversalpublic class AVLTree … {

public void inorder(final Visitor<T> v) {inorder(v, root);

}

interface Visitor<T extends Comparable<T>> {void visit(T n);

}

private void inorder(Visitor<T> v, Node<T> n) {if (n == null)

return;inorder(v, n.left);v.visit(n.data);inorder(v, n.right);

}…}

Page 17: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Tree Invariantpublic class AVLTree … implements Checkable {

@Override public void invariant() {inorder(new Visitor<T>() {

T previous = null;

@Override public void visit(T current) {if (previous != null)

positive(current.compareTo(previous));previous = current;

}});if (root != null)

root.invariant();}static class Node<T extends Comparable<T>>

implements Checkable {@Override public void invariant() { … }

}}

Page 18: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Node Invariantpublic class AVLTree …{static class Node<T… > implements Checkable {

Node<T> left, right;T data;BalancingState b = BalancingState.BALANCED;@Override public void invariant() {

final int hl = height(left); nonnegative(hl);final int hr = height(right); nonnegative(hr);switch (hl - hr) {case 1: sure(b == BalancingState.LEFT); break;case 0: sure(b == BalancingState.BALANCED); break;case -1: sure(b == BalancingState.RIGHT); break; default: unreachable();}

if (right != null) right.invariant();if (left != null) left.invariant(); }

}}

Page 19: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Insertion

public class AVLTree …{private static <T…> Node<T> insert(T x, Node<T> n) {if (n == null)return new Node<T>(x);

final int comparison = x.compareTo(n.data);if (comparison == 0) // Found in tree, do nothing.return n;

if (comparison < 0)n.left = insert(x, n.left);

elsen.right = insert(x, n.right);

return n;}

}

Page 20: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Insertionpublic class AVLTree …{public void insert(final T x) {if (find(x) != null) // No need for insertion, nor for rebalancingreturn;

root = insert(x, root);…

}private static <T…> Node<T> insert(T x, Node<T> n) {if (n == null)return new Node<T>(x);

final int comparison = x.compareTo(n.data);if (comparison == 0) // Found in tree, do nothing.return n;

if (comparison < 0)n.left = insert(x, n.left);

elsen.right = insert(x, n.right);

return n;}

}

Page 21: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Rebalancingpublic class AVLTree …{public void insert(final T x) {…root = Defaults.to(balance(root, x), root);

}private static <T ….> Node<T> balance(Node<T> n, T x) {comparison = x.compareTo(n.data);if (comparison == 0) // This is the leaf where the node was inserted.return null;

if (comparison < 0) { // Node was inserted to the left of this nodeNode<T> newLeft = balance(n.left, x);if (newLeft == null) // Height of left subtree increasedreturn n.tipLeft();

n.left = newLeft;return n;

}// Node was inserted to the right of this node…}

}

Page 22: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Delegation to State

public class AVLTree …{

static class Node<T…> {BalancingState b = BalancingState.BALANCED;Node<T> tipLeft() {return b.tipLeft(this);

}

Node<T> tipRight() {return b.tipRight(this);

}}

}

Page 23: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Balancing Factor and the State Patternpublic class AVLTree …{static class Node<T… > implements Checkable {BalancingState b = BalancingState.BALANCED;enum BalancingState {

BALANCED { public <T …> Node<T> tipLeft(Node<T> me) {

me.setState(LEFT);return null; // height has increased

}public <T …> Node<T> tipRight(Node<T> me) {

me.setState(RIGHT);return null; // height has increased

}},LEFT {…},RIGHT {…};public abstract <T…> Node<T> tipLeft(Node<T> n);public abstract <T…> Node<T> tipRight(Node<T> n);

}}}

Page 24: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Actions in an Unbalanced Nodepublic class AVLTree …{static class Node<T… > implements Checkable {BalancingState b = BalancingState.BALANCED;enum BalancingState {

BALANCED {…},LEFT {

public <T …> Node<T> tipRight(Node<T> me) {return me.setState(BALANCED); // height did not change

}public <T …> Node<T> tipLeft(Node<T> me) {

return me.left.pivotLeft(me); // height did not change}

},RIGHT {…};public abstract <T…> Node<T> tipLeft(Node<T> n);public abstract <T …B> Node<T> tipRight(Node<T> n);

}}}

Page 25: The State Design Pattern Idea: internal state == Object Intent: Allow an object to alter its behaviour when its internal state changes. The object will

Delegating Rotation Responsibilityclass AVLTree {static class Node …{

Node<T> pivotLeft(Node<T> parent) {return b.pivotLeft(this, parent);

}enum BalancingState {

BALANCED {…},LEFT {

public <T …> Node<T> tipLeft(Node<T> me) {return me.left.pivotLeft(me); // height did not change

}Node<T> pivotLeft(Node<T> me, Node<T> parent) {

// LEFT LEFT balancing}

},RIGHT {…};<…> Node<T> pivotLeft(Node<T> me,Node<T> parent) {// Default implementation, setting the method contractnonnull(parent);nonnull(me);require(parent.left == me);return parent;

}}}}