Archive

Archive for December, 2011

From ActionScript 3.0 to JavaScript Chain of Responsibility: Part I

December 26, 2011 1 comment

After Mom, Ask Dad, and then the Dog

After Mom, Ask Dad, and then the Dog

Just Follow the Chain of Responsibility

To get started on the quest to see whether useful design patterns can be created with JavaScript, I thought it’d be a good idea to go from the known to the unknown. In this case, those familiar with this blog know ActionScript 3.0 design patterns, and the unknown (for some at least) is JavaScript. Well, I suppose just about everyone who reads this blog knows something about JavaScript, but several may not have been involved with either JavaScript OOP or design patterns. By creating an ActionScript 3.0 app using a pattern and then going through the app step-by-step, readers may be better able to understand how we might approach design patterns using JavaScript. I decided to use the Chain of Responsibility (CoR) pattern to go through the types of mobile operating systems that we examined in the previous post. In this way, we can create something both familiar and practical.

Every time I use the Chain of Responsibility pattern, I feel that I’m swatting a fly with a weapon of mass destruction. I see all of these classes, and I’m thinking that I could have done the same thing with a switch statement or something even slicker. Then I need to remind myself why I’d use the CoR in the first place.

The Chain of Responsibility separates the handling of an event from the request to handle it.

In a broader context, this allows the developer to make changes to either the request or the handling of the event without disrupting some other part of the program. It’s quite simple as well. Just imagine several people lined up with different kinds of expertise and/or authority. A request is issued, and once it reaches the person with the right expertise or authority, it is handled. The request is separated from the way it will be handled. That’s up to the expert. Figure 1 shows the class design:

<em><strong>Figure 1: </strong> Chain of Responsibility Pattern</em>

Figure 1: Chain of Responsibility Pattern

Getting Started with CoR

For details about ways to setup and use CoR see our original discussion . The focal points are in the following:

  • An interface (an abstract class or interface) establishes a handler operation
  • Each request handler has a separate class derived from the handler interface
  • Each handler class has a successor which is another handler class
  • The last handler in the chain has no successor
  • As soon as a handler can handle the request, the chain stops and the handler takes care of the request.

You may be thinking that this is not very efficient since it requires a sequential path. We’ve considered ways to get around a sequence (see our posts on Skip Lists), but for now we’ll stick with the traditional CoR and use a sequential search through the list of handlers.

The Chain of Mobile Operating Systems

This CoR simulates finding one of several types of mobile OS. Given the type of OS, it looks for ways to handle each one optimally. In the JavaScript version of this, we want to have it select a CSS file or another JS file to best use the kind of mobile device involved. The concrete handler classes are the objects used to deal with whatever requirements are necessary. In the example, each handler simply traces out “Set up for xxOS,” where “xx” is the found mobile OS. It also traces out which handlers were rejected so that you can better see how the chain works. Since Android is at the top of the chain, you see no rejections, while Windows CE at the bottom of the chain displays the whole chain.

It might be helpful if you take a look at the whole concept of Linked Lists. The Chain of Responsibility is something like a linked list, but instead of linking lists, it links handlers.

The Client class makes the initial request and sets up a simple requesting UI for testing the application. It makes requests using a string. I just used the lowercase ID of the main mobile OS types as the “request-to-handle.” After making the request, the “chain” takes over. In this example the top of the chain is the Android, but it could be any of the others as well. The developer has complete control over the sequence.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import fl.controls.Button;
	import fl.controls.TextInput;
	import fl.controls.Label;
	import flash.text.TextFieldAutoSize;
 
	public class Client extends Sprite
	{
		//Handlers + Request
		private var android:Handler= new Android();
		private var iphone:Handler= new IPhone();
		private var blackberry:Handler= new Blackberry();
		private var series60:Handler=new Series60();
		private var windowsce:Handler=new WindowsCE();
		private var cannothandle:Handler=new CannotHandle();
 
		//UI
		private var btn:Button=new Button();
		private var iput:TextInput=new TextInput();
		private var lbl:Label=new Label();
 
		public function Client()
		{
			setupChain();
			setupUI();
		}
 
		private function setupChain():void
		{
			//Sequence set up here
			android.SetSuccessor(iphone);
			iphone.SetSuccessor(blackberry);
			blackberry.SetSuccessor(series60);
			series60.SetSuccessor(windowsce);
			windowsce.SetSuccessor(cannothandle);
		}
 
		private function setupUI():void
		{
			//This simulates getting the mobile OS from the using system
			lbl.autoSize = TextFieldAutoSize.LEFT;
			lbl.text="Enter name of mobile device: (Use lower case.)";
			lbl.x=50,lbl.y=30;
			addChild(lbl);
			btn.x=50, btn.y=75;
			btn.label="Start the chain";
			btn.addEventListener(MouseEvent.CLICK,requestOS);
			addChild(btn);
			iput.x=50,iput.y=50;
			addChild(iput);
		}
 
		private function requestOS(e:MouseEvent)
		{
			android.HandleRequest(iput.text);
		}
	}
}

For the end of the chain, I added a “CannotHandle” class that extends the Handler interface. This functions something like a default option in a switch statement. If none of the handlers can handle the request, you need to provide the user with some kind of feedback.
Read more…

Share