JavaScript: Module, Observable, and Methods-as-Properties Patterns
var Book = (function(){ // Private var _name; var _price; var priceChanging = []; var priceChanged = []; var updatePriceChanging = function(_this, value){ for (var i = 0; i < priceChanging.length; ++i){ if (!priceChanging[i](this, value)){ return true; } } return false; } var updatePriceChanged = function(_this){ for (var i = 0; i < priceChanged.length; ++i){ priceChanged[i](_this); } } //Public return { factory(name, price){ _name = name; _price = price; return this; } ,name: function(){ return _name; } , price: function(value){ if (value !== undefined && value != _price){ var isPriceTooHigh = updatePriceChanging(this, value) if (isPriceTooHigh){ return _price; } _price = value; updatePriceChanged(this); } return _price; } ,onPriceChanging: function(callback){ priceChanging.push(callback); } , onPriceChanged: function(callback){ priceChanged.push(callback); } } })(); var book = Book.factory('Lord Of the Rings', 23.99); console.log(book.name()); console.log(book.price()); book.onPriceChanging(function(book, price){ console.log('Changing book price to $' + price); if (price > 100){ console.log('-> [X] Price ($' + price + ") is too high. No changing price"); return false; } return true; }); book.onPriceChanged(function(book){ console.log("The book '" + book.name() + ' changed price to $' + book.price()); }); book.price(19.99); book.price(200.00); book.price(99.01);
Output:
Lord Of the Rings 23.99 Changing book price to $19.99 The book 'Lord Of the Rings changed price to $19.99 Changing book price to $200 [X] Price ($200) is too high. No changing price Changing book price to $99.01 The book 'Lord Of the Rings changed price to $99.01
Strategy Pattern
NOTIFICATION: These examples are provided for educational purposes. The use of this code and/or information is under your own responsibility and risk. The information and/or code is given ‘as is’. I do not take responsibilities of how they are used.
Strategy pattern is the encapsulation of each algorithm in such a way that we can interchange them as best fit our needs.
The main objective of this pattern is to apply in the best way possible Object Oriented principles such as abstraction, encapsulation, inheritance, and polymorphism using the following design principles:
|
Normally, I would walk you step-by-step until you get to the big picture; however, we are going to do a different approach.
First I am going to show you the forest and then we are going to see each tree individually.
Lets assume that you company is a pet store which wishes to show online its products.
As an experiment, the company decide to sell all type of dogs (such real dogs, ceramic dogs, and toy dogs) and different species of dogs (such as chihuahuas, great Danes and pugs).
The UML diagram displayed on the left, shows how the strategy pattern works. Please notice that we have the super-class called Dog. We could have called the super-class Animal and have a sub-class called Dog. Then we could create other sub-classes such as the Cat class; however, we are concentrating on Dogs to simplify the explanation.
Lets begin with the Dog super-class.This class have behaviors that all dogs may or not able to do. This super-class HAS-A interface for barking and jumping. The interfaces allow us to point to different algorithms. For example, this class have an interface called “interfaceJumping” which allow us to point to different jumping algorithms: the jump high, jump low and do not jump algorithm. By using the method setJumping(), we can tell this class which jumping algorithm will use when someone calls the method jump().
The three sub-classes below, ChihuahuaDog, CeramicDog and ToyDog inherit methods from the super-class, then you can define a different algorithm for each dog. For example, the chihuahua dog can jump low while the ceramic and toy dog cannot jump. While the chihuahua dog and the toy dog can bark, the ceramic dog cannot bark. Finally, you could add a Great Dane dog which jump higher and have a loud bark if you wish.
Please notice that we are using most of the design principles here. Some few examples are the fact that we are encapsulating those parts that can change such as different jump and barking behaviors. We are using loosely couple design since the classes have, or make use of, with little or no knowledge of the definitions of other separate classes. We have classes that focus only on one task in hand. We were concentrating on programming the interfaces instead of implementing everything in one class and modify the subclasses over and over again. By using composition, we can change the algorithm use for jumping in runtime. We could make the chihuahua jump higher instead of jumping lower depending of the kind of Chihuahua we wish to sell. We only need to pass the JumpHigh object to the ChihuahuaDog object as a parameter for setJumping() and it is done! Every time the jump() method is called, the ChihuahuaDog object will use the JumpHigh object making our Chihuahua jump higher instead of lower. Maybe our chihuahua got a broken leg that didn’t heal, then we can use the DoNotJump object for that particular chihuahua.
How about we see the code for this pattern?
Lets first create the interfaces:
public interface InterfaceBarking { public void bark(); }
public interface InterfaceJumping { public void jump(); }
Second, we create all the algorithms related with barking and jumping using the interfaces we created previously:
public class JumpHigh implements InterfaceJumping { @Override public void jump() { System.out.println("I am jumping high!"); } }
public class JumpLow implements InterfaceJumping { @Override public void jump() { System.out.println("I am jumping low!"); } }
public class DoNotJump implements InterfaceJumping { @Override public void jump() { System.out.println("I cannot jump!"); } }
public class BarkLoud implements InterfaceBarking { @Override public void bark() { System.out.println("I am barking loud! BARK! BARK! BARK!"); } }
public class BarkSoft implements InterfaceBarking { @Override public void bark() { System.out.println("I am barking soft. jip! jip! jip!"); } }
public class DoNotBark implements InterfaceBarking { @Override public void bark() { System.out.println("(I cannot bark)"); } }
Third, we are going to create the super-class Dog (One Dog to rule them all, One Dog to find them, One Dog to bring them all and in the program bind them):
public abstract class Dog { // ASCII image done by JG private final String strDogImageASCII = " |\\\n" +" \\`-. _.._| \\\n" +" |_,' __`. \\\n" +" (.\\ _/.| _ |\n" +" ,' __ \\ |\n" +" ,' __/||\\ |\n" +"(O8O ,/|||||/ |\n" +" `-'_---- /\n" +" /`-._.-'/\n" +" `-.__.-' \n"; protected InterfaceBarking interfaceBarking; protected InterfaceJumping interfaceJumping; public Dog(){ System.out.println("I am a dog\n" + strDogImageASCII); } public abstract void show(); public void bark(){ interfaceBarking.bark(); } public void jump(){ interfaceJumping.jump(); } public void setBarking(InterfaceBarking newInterfaceBarking){ this.interfaceBarking = newInterfaceBarking; } public void setJumping(InterfaceJumping newInterfaceJumping){ this.interfaceJumping = newInterfaceJumping; } }
Fourth, we are going to create the sub-classes ChihuahuaDog, CeramicDog and Toy Dog:
public class ChihuahuaDog extends Dog { public ChihuahuaDog(){ System.out.println("I am a chihuahua dog!\n"); interfaceBarking = new BarkSoft(); interfaceJumping = new JumpLow(); } @Override public void show() { System.out.println("Showing chihuahua dog!"); } }
public class CeramicDog extends Dog { public CeramicDog(){ System.out.println("I am a ceramic dog!\n"); interfaceBarking = new DoNotBark(); interfaceJumping = new DoNotJump(); } @Override public void show() { System.out.println("Showing ceramic dog!"); } }
public class ToyDog extends Dog { public ToyDog(){ System.out.println("I am a toy dog!\n"); interfaceBarking = new BarkLoud(); interfaceJumping = new DoNotJump(); } @Override public void show() { // TODO Auto-generated method stub System.out.println("Showing toy dog!"); } }
Finally, we going to create the class DogProducts which would use all these work we have done so far:
DogProducts.java
import java.util.ArrayList; import java.util.List; public class DogProducts { /** * @param args */ public static void main(String[] args) { // We are creating a list of dogs List<Dog> dogList = new ArrayList<Dog>(); // Adding dogs to the list dogList.add(new ChihuahuaDog()); dogList.add(new CeramicDog()); dogList.add(new ToyDog()); // For each dog in the list, show them and ask them to bark and jump. for (Dog dog : dogList) { dog.show(); dog.bark(); dog.jump(); System.out.println(); } } }
The output would look as follow:
I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a chihuahua dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a ceramic dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a toy dog! Showing chihuahua dog! I am barking soft. jip! jip! jip! I am jumping low! Showing ceramic dog! (I cannot bark) I cannot jump! Showing toy dog! I am barking loud! BARK! BARK! BARK! I cannot jump!
Here is the file of this example: StrategyPatternDogProducts.zip
Now lets say that you wished to do a prank; therefore, we can use the flexibility that our code have. The prank is that each dog will have a random jump and bark.
Lets modify the main driver class:
import java.util.ArrayList; import java.util.List; public class DogProducts { // We are creating a list of dogs private List<Dog> dogList; public DogProducts(){ dogList = new ArrayList<Dog>(); addDogsToList(); } private void addDogsToList(){ // Adding dogs to the list dogList.add(new ChihuahuaDog()); dogList.add(new CeramicDog()); dogList.add(new ToyDog()); } private void show(){ // For each dog in the list, show them and ask them to bark and jump. for (Dog dog : dogList) { dog.show(); dog.bark(); dog.jump(); System.out.println(); } } private void doPrank(){ // Empty List dogList.clear(); // Now the Chihuahua dog will bark loud and jump high LOL Dog chihuahuaDog = new ChihuahuaDog(); chihuahuaDog.setBarking(new BarkLoud()); chihuahuaDog.setJumping(new JumpHigh()); // The ceramic dog is possess. It can bark soft and jump low. LOL Dog ceramicDog = new CeramicDog(); ceramicDog.setBarking(new BarkSoft()); ceramicDog.setJumping(new JumpLow()); // The toy dog cannot bark but it can jump high. How unexpected! LOL Dog toyDog = new ToyDog(); toyDog.setBarking(new DoNotBark()); toyDog.setJumping(new JumpHigh()); dogList.add(chihuahuaDog); dogList.add(ceramicDog); dogList.add(toyDog); } /** * @param args */ public static void main(String[] args) { DogProducts dogProducts = new DogProducts(); boolean doPrank = true; if (doPrank){ dogProducts.doPrank(); dogProducts.show(); }else{ dogProducts.show(); } } }
I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a chihuahua dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a ceramic dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a toy dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a chihuahua dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a ceramic dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a toy dog! Showing chihuahua dog! I am barking loud! BARK! BARK! BARK! I am jumping high! Showing ceramic dog! I am barking soft. jip! jip! jip! I am jumping low! Showing toy dog! (I cannot bark) I am jumping high!
Here is the source code: StrategyPatternDogProductsPrank.zip
At the end of this post, we wish to test the changes of the algorithm randomly in run time; therefore, we are going to modify DogProduct.java as follows:
import java.util.ArrayList; import java.util.List; import java.util.Random; public class DogProducts { // We are creating a list of dogs private List<Dog> dogList; public DogProducts(){ dogList = new ArrayList<Dog>(); addDogsToListWithRandomAlgorithms(); } public Random getNewGenerator(){ Random seed = new Random(); return new Random(seed.nextInt()); } private void addDogsToListWithRandomAlgorithms(){ Dog chihuahuaDog = new ChihuahuaDog(); chihuahuaDog.setBarking(getRandomBark()); chihuahuaDog.setJumping(getRandomJump()); dogList.add(chihuahuaDog); Dog ceramicDog = new CeramicDog(); ceramicDog.setBarking(getRandomBark()); ceramicDog.setJumping(getRandomJump()); dogList.add(ceramicDog); Dog toyDog = new ToyDog(); toyDog.setBarking(getRandomBark()); toyDog.setJumping(getRandomJump()); dogList.add(toyDog); } private InterfaceBarking getRandomBark(){ // Getting a new generator increases the chances of getting a true random number int randomBark = getNewGenerator().nextInt(2); switch(randomBark){ case 0: return new BarkLoud(); case 1: return new BarkSoft(); } return new DoNotBark(); } private InterfaceJumping getRandomJump(){ // Getting a new generator increases the chances of getting a true random number int randomJump = getNewGenerator().nextInt(2); switch(randomJump){ case 0: return new JumpHigh(); case 1: return new JumpLow(); } return new DoNotJump(); } private void show(){ // For each dog in the list, show them and ask them to bark and jump. for (Dog dog : dogList) { dog.show(); dog.bark(); dog.jump(); System.out.println(); } } /** * @param args */ public static void main(String[] args) { DogProducts dogProducts = new DogProducts(); dogProducts.show(); } }
I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a chihuahua dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a ceramic dog! I am a dog |\ \`-. _.._| \ |_,' __`. \ (.\ _/.| _ | ,' __ \ | ,' __/||\ | (O8O ,/|||||/ | `-'_---- / /`-._.-'/ `-.__.-' I am a toy dog! Showing chihuahua dog! I am barking soft. jip! jip! jip! I am jumping high! Showing ceramic dog! I am barking loud! BARK! BARK! BARK! I am jumping high! Showing toy dog! I am barking soft. jip! jip! jip! I am jumping low!
Here is the source: StrategyPatternDogProductsRandom.zip
Please leave a comment if you have a question or you wish to provide your feedback.
Classes and Interfaces with ColdFusion
NOTIFICATION: These examples are provided for educational purposes. The use of this code and/or information is under your own responsibility and risk. The information and/or code is given ‘as is’. I do not take responsibilities of how they are used.
I noticed that there is very little talk about patterns and ColdFusion so I decided to talk a little.
First allow me to clarify that patterns are not solid rules, they are just suggestions on how to deal with common problems. You can combine different patterns as well to modify a pattern to fit your needs.
For the purpose of this lesson, lets assume that you are working for a company that develop pet simulators; also, lets assume that you work in a team together with many developers.
You company wish to create a dog simulator which allows us show different type of dogs and dog species.
Originally, we could have use standard Object Oriented techniques and created on Dog super-class from which each dog species inherit the basic functions:
In ColdFusion, your code would similar to the following (I am only writing the super-class and sub-classes):
File Dog.cfc:
<!--- Dog.cfc ---> <cfcomponent name="Dog"> <cffunction name="bark"> <!--- Your code ---> </cffunction> <cffunction name="run"> <!--- Your code ---> </cffunction> </cfcomponent>
ChihuahuaDog.cfc
<!--- ChihuahuaDog.cfc ---> <cfcomponent name="ChihuahuaDog" extends="Dog"> <cffunction name="display"> <!--- Your code ---> </cffunction> </cfcomponent>
Now this is a super-class and subclasses as an example that the rest of programmers are going to be adding different species of dogs.
Out of the blue, one of the managers come with the idea to add a new functionality: jump();
So you say to yourself that you only need to add a jump method to the Dog class then all the different dogs will inherit this function.
Everything goes well until until one of the managers approach you in a very aggressive matter. This manager is angry at you because when presenting the demo of the software he finish doing a fool of himself. The reason was that someone requested to add a ceramic dog. When the manager was presenting the software, ceramic dogs where jumping everywhere when they are not supposed to be able to jump in the first place! In order work, when you added the extra function, you were adding a behavior that should be applied to some sub-classes.
So you think that you could just override the jump() method in in the ToyDog subclass that way you don’t have to worry about it.
However, the ceramic dog cannot bark nor run either. So you do the same as you did with the jump() function. Later on, someone decided that they need to add a toy dog which cannot run, but it can bark, jump, and grow its eyes! You are starting to realize that in any moment someone may decided to add some type of dog that you were not thinking that could exist. Perhaps using inheritance was not great idea after all!
So following the previous idea would result in a maintenance nightmare. The more type and species your company keeps adding, the more maintenance is required; therefore, a new idea shows up in your head: “How about using interfaces?”
Think about interfaces as an standard that when establish everyone must follow. A construction, for example, follow different standards and many constructions are different one from the other with different requirements. For some things, they may share similarities, but for others, they can be different. While many constructions may share the fact that they use cement for their base, the wall could be build from a different material which must follow an establish standard. If this example doesn’t help you, please leave a comment and I will try to come up with something else. |
By using interfaces, you could take out those functions such as bark(), run() and jump() that may not we usable and leave those functions that will be use the more sure. In that way when a dog is supposed to jump, then you can implement the interface and have have the jump method.
Think that interface allow you do define behaviors for your classes.
In ColdFusion, we can use interfaces, for example:
The following is the InterfaceBarking.cfc file:
<cfinterface name="InterfaceBarking" hint="Defines the a barking interface for a dog."> <cffunction name="bark" access="public" returntype="any" output="false" hint="Allows the dog to bark."> </cffunction> </cfinterface>
Now the ChihuahuaDog.cfc may look like the follow:
<!--- ChihuahuaDog.cfc ---> <cfcomponent name="ChihuahuaDog" extends="Dog" Implements="InterfaceBarking"> <cffunction name="display"> <!--- Your code ---> </cffunction> <cffunction name="bark"> <!--- Your code ---> </cffunction> </cfcomponent>
Extends points to the parent class (super-class) and Implements points to the interface
At this point is good to introduce a design principle so we can remember in the future:
First identify which aspect of the program may vary and separate them from the rest that will stay the same. |
In other words, in order to not affect the rest of your code, take those components that variate and encapsulate them. In this way, you don’t produce unpredicted behaviors. Also, this introduce us to another design principle:
Do not program the implementation but the interface instead. |
NOTIFICATION: This is a draft and I will be keep working on it.