Strategy Pattern

Strategy Pattern is my favorite one, and why?
because it’s so simple for implamentation; it’s based on polymorphism, an the basic idea is to encapsulate the code that you think is gonna change.

for example let’s say that you have and Encryptor Class:

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
package 
{
 
	/**
	 * ...
	 * @author Raúl Uranga
	 */
	public class EncryptorManager
	{
	/**
	* Encodes a base64 string.
	*/
	public function encodeMessage(src:String):String {
		var i:Number = 0;
		var output:String = new String("");
		var chr1:Number, chr2:Number, chr3:Number;
		var enc1:Number, enc2:Number, enc3:Number, enc4:Number;
		while (i < src.length) {
			chr1 = src.charCodeAt(i++);
			chr2 = src.charCodeAt(i++);
			chr3 = src.charCodeAt(i++);
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
			if(isNaN(chr2)) enc3 = enc4 = 64;
			else if(isNaN(chr3)) enc4 = 64;
			output += base64chars.charAt(enc1)+base64chars.charAt(enc2);
			output += base64chars.charAt(enc3)+base64chars.charAt(enc4)
		}
		return output;
	}
 
	/**
	* Decodes a base64 string.
	*/
	public function decodeMessage(src:String):String {
		var i:Number = 0;
		var output:String = new String("");
		var chr1:Number, chr2:Number, chr3:Number;
		var enc1:Number, enc2:Number, enc3:Number, enc4:Number;
		while (i < src.length) {
			enc1 = base64chars.indexOf(src.charAt(i++));
			enc2 = base64chars.indexOf(src.charAt(i++));
			enc3 = base64chars.indexOf(src.charAt(i++));
			enc4 = base64chars.indexOf(src.charAt(i++));
			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
			output += String.fromCharCode(chr1);
			if (enc3 != 64) output = output+String.fromCharCode(chr2);
			if (enc4 != 64) output = output+String.fromCharCode(chr3);
		}
		return output;
	}	
	}
}

usage:

1
2
3
4
5
var customEncryptor:EncryptorManager= new EncryptorManager();
var encodedMessage:String = customEncryptor.encodeMessage("my secret message hehehe");
 
trace(encodedMessage);
trace("message: ", customEncryptor.decodeMessage(encodedMessage) );

so, you can see here that the Encryptor Manager uses Base64 for encode and decode messages but, the client with a smile in his face, is telling you that the application no longer use Base64 and it needs to change it……..
well, the first thing that comes to your head is: “ok, i just need to change this two methods and i can continue learning salsa with AS3” XD, but what if it needs to change again and again??

we are a lazy but smart ones developers =D so we are going to implement the Strategy Pattern

first we create an Interface that would be implemented by our custom encryptors

1
2
3
4
5
6
7
8
package 
{
	public interface IEncryptor
	{
		public function encode(src:String):String;
		public function decode(src:String):String;
	}
}

then we encapsulate the code that’s is going to change in another class

Base64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package 
{
	public class Base64Encryptor implements IEncryptor
	{
 
	        public function encode(src:String):String {
		     // Base 64 implementation code goes here
	        }
 
	        public function decode(src:String):String {
		     // Base 64 implementation code goes here
	        }	
        }
}

LZW

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package 
{
	public class LZWEncryptor implements IEncryptor
	{
 
	public function encode(src:String):String {
 
		 //  LZW implementation code goes here
	}
 
	public function decode(src:String):String {
		//  LZW implementation code goes here
	}
        }
}

MD5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package 
{
	public class MD5Encryptor implements IEncryptor
	{
 
	        public function encode(src:String):String {
		     // MD5  implementation code goes here
	        }
 
	        public function decode(src:String):String {
		     // MD5  implementation code goes here
	        }	
        }
}

now we need to change a little bit our EncryptorClass to manage these new encryptors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package 
{
	public var encrytor:IEncryptor;
 
	public class EncryptorClass (encrytor:IEncryptor = new NullEncryptor())
	{
		this.encrytor = encrytor;
	}
 
	public function encodeMessage(src:String):String {
		return encrytor.encode(src); // this is where the magic happends!!
	}
 
 
	public static function decodeMessage(src:String):String {
		return encrytor.decode (src); // this is where the magic happends!!
	}
}

and here it goes the new implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
var _base64encry:IEncryptor = new Base64Encryptor();
 
var customEncryptor:EncryptorManager= new EncryptorManager();
customEncryptor.encrytor = _base64encry;
var encodedMessage:String = customEncryptor.encodeMessage("my secret message hehehe");
var decodedMessage = customEncryptor.decodeMessage(encodedMessage);
 
trace("Encoded Message : ", encodedMessage );
trace("Decoded Message : ", decodedMessage );
.
.
.
//now we can switch the encrytor algorithm just creating new Encrytor instances
customEncryptor.encrytor = new LZWEncryptor() ;
 
encodedMessage = customEncryptor.encodeMessage("my secret message hehehe");
decodedMessage = customEncryptor.decodeMessage(encodedMessage);
 
trace("Encoded Message : ", encodedMessage );
trace("Decoded Message : ", decodedMessage );

you can now create new Encrytor instances by just implementing the IEncrytor interface, and switch them with out a change in the EncryptorManager ClassXD.

This entry was posted in General and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. zim22
    Posted 16 January 2010 at 4:40 | Permalink

    thanks for your explanation of Strategy Pattern. It’s awesome.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*