1. Trang chủ
  2. » Giáo án - Bài giảng

6-Behavioral Design Patterns.ppt

62 567 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 62
Dung lượng 382 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

an action from the object that actually performs the action  Requester == remote control, Object == vendor classes  Introduce "command objects" into your design.. Coding Our Command Ob

Trang 1

Behavioral design patterns

Trang 3

The Command Pattern

Encapsulating Invocation

Trang 4

The Command Pattern Example

Trang 5

Motivation Example

Program a Remote Control that can be used to

control the devices in the house

Requirements:

 Remote control features seven programmable slots

 Each slot can be assigned to a different household device

 Each slot has a corresponding on/off button

 Remote has a global undo button that undoes the last button pressed

 A set of vendors classes are provided to give you an idea of the interfaces of the objects that need to be controlled from the remote

Trang 6

Global “undo” button

CeilingLight

on ( ) off ( ) dim ( )

TV

on ( ) off ( ) setInputChannel ( ) setVolume ( )

FaucetControl openValue ( ) closeValue ( )

Thermostat setTemperature ( )

Hottub circulate ( ) jetsOn ( ) jetsOff ( ) setTemperature ( ) Vendor Classes

Trang 7

Observations, anyone?

methods > common interface

about home automation or how to turn on a hot tub.

 Any issues? If the remote is dumb, how do we design a remote so that

it can invoke an action - turn on a light?

future - design must accommodate for that

Trang 8

Enter – The Command Pattern!

an action from the object that actually performs the action

 Requester == remote control, Object == vendor classes

 Introduce "command objects" into your design A command object

encapsulates a request to do something (like turn on a light) on a

specific object (say, the living room light).

 Every time a remote button is pressed, its corresponding command

object goes to work!

 Remote does not have any idea what the work is, it just has a command object that knows how to talk to the right object to get the work done.

Here the remote is decoupled from the object!

Trang 9

Simple Remote Control: Only one button

Trang 10

Coding Our Command Object

Command Interface:

}

Implementing a Command to turn the light on

Light light;

this.light = light;

object, which is the light that we are controlling.

Trang 11

Using the Command Object

We have one slot to hold our command, which will control one device.

Method for setting the command the slot it’s going to control This could be called if the client wanted to change the behavior of the remote button.

This method is called when the button is pressed All we do is take the current command bound to the slot and call its execute() method.

Trang 12

SimpleRemoteControl remote = new

SimpleRemoteControl();

Light light = new Light();

LightOnCommand lightOn = new LightOnCommand(light);

create a Light Object - the Receiver of the request.

create a command and pass it to the Receiver.

pass the command to the Invoker.

simulate the button being pressed.

Trang 13

invoking the corresponding operation(s) on Receiver

Knows how to perform the

operations associated with

carrying out a request Any

class may serve as a Receiver

The Command Pattern encapsulates a request as an object, thereby

letting you parameterize other objects with different requests, queue

or log requests, and support undoable operations.

Trang 14

Applicability

Use the Command pattern when you want to

function.

The Command's execute() operation can store state for reversing

its effects in the command itself

The Command interface must have an added unexecute()

operation that reverses the effects of a previous call to execute()

case of a system crash

By augmenting the Command interface with load() and store()

operations, you can keep a persistent log of changes

 Recovering from a crash involves reloading logged commands from

disk and reexecuting them with the execute() operation

Trang 15

The Remote Control Example

Trang 16

onCommands = new Command[7];

offCommands = new Command[7];

Command noCommand = new NoCommand();

for (int i = 0; i < 7; i++) {

Implementing the RemoteControl

This time around the remote is going to handle seven On and Off Commands which we will hold in the corresponding array.

In the constructor all we need to do

is instantiate the on and off arrays.

The setCommand() method takes a slot position and an

On and Off command to be stored in that slot It puts these commands in the On and Off array for later use.

When an On or a Off button is pressed, the hardware takes care of calling the

corresponding methods

Trang 17

public StereoOnWithCDCommand (Stereo stereo) {

this.stereo = stereo;

Implementing the Commands

The LightOffCommand works exactly like the

LightOnCommand, except that we are binding

the receiver to a different action: the off()

command.

An instance of the stereo we are going

to control is passed

to constructor

To carry out this request we need to call three methods on the stereo:

first, turn it on, then set it to play the

CD, and finally set the volume to 11 !

Trang 18

public class RemoteLoader {

public static void main(String[] args) {

RemoteControl remoteControl = new RemoteControl();

Light livingRoomLight = new Light( "Living Room" );

Create all the Command objects Load the command objects

Ready to roll! Test out the remote!

Trang 19

command was loaded for every slot

To get around it, we introduce a "NoCommand" object

Fixing the RemoteControl constructor:

public void onButtonWasPushed(int slot) {

if (onCommands[slot] != null ){

onCommands[slot].execute(); }

}

public class NoCommand implements Command {

public void execute() { };

}

Command noCommand = new NoCommand();

for (int i =0; i < 7; i++ ){

Trang 20

public class LightOnCommand implements Command {

public LightOnCommand (Light light){

this.light = light;

method that mirrors the execute() method Whatever execute() last did, undo() reverses it

Adding the Undo Feature

execute() turns the light on so undo turns it off Reverse for LightOffCommand.

public interface Command {

public void execute();

public void undo();

}

Trang 21

onCommands = new Command[7];

offCommands = new Command[7];

Command noCommand = new NoCommand();

for (int i = 0; i < 7; i++) {

Updating the RemoteControl class

This is where we will stash the last command executed for the undo button

Just like the other slots this is initialized

to a NoCommand.

To add support for the undo button

Trang 22

When the button is pressed

we take the command and first execute it; then we save

a reference to it in the undoCommand instance variable We do this for both

“on” and “off” commands.

When the undo button is pressed, we invoke the undo() method of the command stored in the

undoCommand This reverses the operation that was last executed.

Trang 23

public class CeilingFan {

public static final int HIGH = 3;

public static final int MEDIUM = 2;

public static final int LOW = 1;

public static final int OFF = 0;

String location;

int speed;

public CeilingFan(String location) {

this.location = location;

speed = OFF; }

public void high() {

speed = HIGH;

System.out.println(location + " ceiling fan is on high"); }

public void medium() {

speed = MEDIUM;

System.out.println(location + " ceiling fan is on medium"); }

public void low() {

speed = LOW;

System.out.println(location + " ceiling fan is on low"); }

public void off() {

speed = OFF;

System.out.println(location + " ceiling fan is off"); }

public int getSpeed() {

return speed; }

}

Using State to Implement Undo

Holds local state

Set the speed of the ceiling fan.

Can get the current speed.

Trang 24

public CeilingFanHighCommand(CeilingFan ceilingFan) {

this.ceilingFan = ceilingFan;

Adding Undo to Ceiling Fan Commands

Added local state to keep track of the previous speed of the fan.

In execute(), before we change the speed we need to first record its previous state, just in case we need to undo our actions.

To undo, we set the speed of the fan back

to its previous state.

Trang 25

Command[] commands;

this.commands = commands;

}

public void execute(){

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

MacroCommand

When the macro gets executed by the remote, execute those commands one

at a time.

Executing multiple commands with one

 Push one button to dim the lights, turn on the stereo and the

TV and set the to DVD

Trang 26

Macro Command

Composite of commands

Trang 27

More Uses - Queuing Requests

computation and pass it around as a first-class object.

 Add commands to the queue on one end, and on the other end sits a group of threads

 Threads run the following script:

 Remove command from the queue

 Call its execute method

 Wait for the call to finish

 Discard the command object and retrieve the new one.

that are doing the computation.

Trang 28

More Uses: Logging Requests

Semantics of some applications require that we log all actions and be able to recover after a crash by re-invoking those actions

The Command Pattern can store these semantics with the addition of two new methods: store() and load()

 In Java we could use serialization to implement this

How does it work?

 As execute commands, we store a history of them on disk

 When a crash occurs, we reload the command objects and invoke their execute() methods in batch and in order

Trang 29

Summary

The Command pattern decouples an object making a request from one that knows how to perform it.

A Command object is at the center of this decoupling and encapsulates

a receiver with an action (or set of actions)

An invoker makes a request of a Command object by calling its

execute () method, which invokes those actions on the receiver.

Invokers can be parameterized with the Commands, even dynamically

at runtime.

Commands may support undo by implementing an undo method that restores the object to its previous state before the execute ( ) method was last called.

Macro commands are a simple extension of Command that allow

multiple commands to be invoked.

Commands may also be used to implement logging and transactional systems.

Trang 30

Observer Pattern

Keeping your Objects in the Know!

Trang 31

Motivation Weather Station

 Weather Station – hardware device which collects data from various sensors (humidity, temperature, pressure)

 WeatherData object which interfaces with the Weather Station

hardware

WeatherData and must be updated each time

WeatherData has new measurements

 a current conditions display Temp, Humidity, Pressure change

 a weather statistics display Avg temp, Min temp, Max temp

 and a forecast display

 can create new custom display elements and can add or remove as many display elements as they want to the application

Trang 32

Pulls data Displays

Current conditions is one of three different displays The user can also get weather stats and a forecast.

Display Devices

Current Conditions

Temp: 72 Humidity: 60 Pressure:

Current Conditions

Temp: 72 Humidity: 60 Pressure:

Weather Data Object Statistics

Avg Temp: 70 Avg Humidity: 63 Avg Pressure:

Statistics

Avg Temp: 70 Avg Humidity: 63 Avg Pressure:

Trang 33

We don’t care HOW these variables are set; the WeatherData object knows how to get updated information from the Weather Station

This method is called anytime new weather measurement data

is available

Trang 34

// instance variable declarations

currentConditionsDisplay.update(

temp, humidity, pressure);

statisticsDisplay.update(temp, humidity, pressure);

forecastDisplay.update(temp, humidity, pressure);

methods (already implemented)

Now update the displays.

Call each display element to update its display, passing it the most recent measurements

Trang 35

public class WeatherData {

// instance variable declarations

public void measurementsChanged() {

float temp = getTemperature();

float humidity = getHumidity();

float pressure = getPressure();

currentConditionsDisplay.update(temp, humidity, pressure); statisticsDisplay.update(temp, humidity, pressure);

forecastDisplay.update(temp, humidity, pressure);

Area of change, we need

to encapsulate this.

By coding to concrete implementations

we have no way to add or remove other

display elements without making changes

to the program.

Trang 36

The Observer Pattern

OO Design Principle

Strive for loosely coupled designs

between objects that interact.

 Loosely coupled designs allow us to build flexible OO

systems that can handle changes because they minimize the interdependency between objects

The Observer Pattern (Intent)

 Define a one-to-many dependency between objects so that when one object changes state, all its dependents are

notified and updated automatically

Trang 38

Structure Observer Pattern

Knows its numerous observers Provides an interface for

attaching and detaching observer objects

Sends a notification to its observers when its state changes.

Defines an Update interface for concrete observers, that gets called when the

Subject’s state changes.

Concrete observers can be any class that implements the Observer interface Each observer registers with a concrete subject to receive updates.

A concrete subject always implements the Subject interface

In addition to the register (attach) and remove (detach)

methods, the concrete subject implements a notify() method

to notify observers whenever state changes.

Trang 40

}

public void update(float temp, float humidity,

float pressure);

}

}

Implementing the Weather Station

These are the state values the Observers get from the Subject when a weather measurement changes.

Trang 41

public class WeatherData implements Subject {

private ArrayList observers;

private float temperature ;

private float humidity ;

private float pressure ;

public void notifyObservers() {

for (int j = 0; j < observers.size(); j++) {

Observer observer = (Observer) observers.get(j);

observer.update( temperature , humidity , pressure );

Implementing the Subject Interface

Added an ArrayList to hold the Observers, and we create it in the constructor

Notify the observers when measurements change

Here we implement the Subject Interface

Trang 42

implements Observer, DisplayElement {

weatherData.registerObserver(this);

}

float pressure) {

this humidity = humidity;

display();

}

System.out.println( "Current conditions : "

+ temperature + "F degrees and "

+ humidity + "% humidity" );

}

}

The Display Elements

The constructors passed the weatherData object (the subject) and we use it to register the

display as an observer.

When update ( ) is called,

we save the temp and humidity and call display ( )

Trang 43

Using Java’s Built-in Observer Pattern

For an Object to become an Observer:

Implement the java.util.Observer interface and call addObserver() on any Observable object To remove use deleteObserver() method.

For the Observable to send notifications

Extend java.util.Observable superclass

 Then a 2 step process:

1. First call the setChanged() method to signify that the state has

changed in your object.

2. call one of two methods: notifyObservers() or

notifyObservers(Object arg)

For the Observer to receive notifications

 Implement the update() method as before

update(Observable o, Object arg)

Ngày đăng: 16/07/2014, 04:00

TỪ KHÓA LIÊN QUAN

w