Top Banner
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.
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.

Jan 01, 2016

Download

Documents

Francis Owens
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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;

}}}}