JavaScript - tutorial - 19 - design patterns

Revision:


Content

what are design patterns? creational design patterns structural design patterns behavioral design patterns


what are design patterns?

top

Design patterns are the solutions to commonly occurring problems in software design. These patterns are easily re-usable and are expressive.

Benefits of design patterns:

they are the best solutions, used by developers because they know that it would work.

they are reusable and can be modified under certain circumstances to solve multiple problems.

they are expressive and need no further explanation, because they can explain the large problem to bits and pieces quite efficiently.

they enhance communication, as developers can set common goals to a problem which helps them to communicate with each other about the potential threats and solutions to those problems.

no code refactoring, as the generated solution is the only efficient solution.

they lower codebase size as they preserve precious space by implementing a required solution in a few lines of code.

Types of patterns: creational, structural, behavioral


creational design patterns

top

These will create objects instead of instantiating an object directly. They deal with the creation of mechanisms that optimize class-object complexities into simple and easy patterns.

constructor method: facilitates the constructor creation.

examples

code:
                    <div class="spec">
                        <p id="ex-01"></p>
                    </div>
                    <script>
                        class Automobile {  
                            constructor(brand, mileage) {  
                                this.brand = brand;  
                                this.mileage = mileage;  
                                this.getDetails = function () {  
                                    document.getElementById("ex-01").innerHTML = `${this.brand} gives ${this.mileage}kmpl!`;  
                                };  
                            }  
                        }  
                        const Automobile1 = new Automobile('Mercedes',20.8);  
                        Automobile1.getDetails();   
                    </script>
                

factory method : defines an interface for creating a single object and lets child classes decide which class to instantiate.

examples

code:
                    <div class="grid">
                        <div class="spec">
                            <p id="ex-2"></p>
                            <p id="ex-3"></p>
                            <p id="ex-3-a"></p>
                            <p id="ex-3-b"></p>
                        </div>
                        <script>
                            var Factory = function () {
                                this.createEmployee = function (type) {
                                    var employee;
                                    if (type === "fulltime") {
                                        employee = new FullTime();
                                    } else if (type === "parttime") {
                                        employee = new PartTime();
                                    } else if (type === "temporary") {
                                        employee = new Temporary();
                                    } else if (type === "contractor") {
                                        employee = new Contractor();
                                    }
                                    employee.type = type;
                                    employee.say = function () {
                                        console.log(this.type + ": rate " + this.hourly + "/hour");
                                        document.getElementById("ex-2").innerHTML += this.type + ": rate " 
                                        + this.hourly + "/hour" + "<br>";
                                    }
                                    return employee;
                                }
                            }
                            var FullTime = function () {
                                this.hourly = "$12";
                            };
                            var PartTime = function () {
                                this.hourly = "$11";
                            };
                            var Temporary = function () {
                                this.hourly = "$10";
                            };
                            var Contractor = function () {
                                this.hourly = "$15";
                            };
                            function run_this() {
                                var employees = [];
                                var factory = new Factory();
            
                                employees.push(factory.createEmployee("fulltime"));
                                employees.push(factory.createEmployee("parttime"));
                                employees.push(factory.createEmployee("temporary"));
                                employees.push(factory.createEmployee("contractor"));
            
                                for (var i = 0, len = employees.length; i < len; i++) {
                                    employees[i].say();
                                }
                            }
                            run_this();
                        </script>
                

abstract factory : creates families or groups of common objects without specifying their concrete classes.

examples

code:
                    <div class="spec">
                        <p id="ex-4-a"></p>
                        <p id="ex-4-b"></p>
                        <p id="ex-4-c"></p>
                    </div>
                    <script>
                        function Employee(name) {
                            this.name = name;
                            this.say = function () {
                                console.log("I am employee " + name);
                                document.getElementById("ex-4-a").innerHTML += "I am employee " + name + "<br>";
                            };
                        }
                        function EmployeeFactory() {
                            this.create = function (name) {
                                return new Employee(name);
                            };
                        }
                        function Vendor(name) {
                            this.name = name;
                            this.say = function () {
                                console.log("I am vendor " + name);
                                document.getElementById("ex-4-b").innerHTML += "I am vendor " + name + "<br>";
                            };
                        }
                        function VendorFactory() {
                            this.create = function (name) {
                                return new Vendor(name);
                            };
                        }
                        function run() {
                            var persons = [];
                            var employeeFactory = new EmployeeFactory();
                            var vendorFactory = new VendorFactory();
        
                            persons.push(employeeFactory.create("Danny Morel"));
                            persons.push(employeeFactory.create("Michel Bloemen"));
                            persons.push(vendorFactory.create("Gerard Quanten"));
                            persons.push(vendorFactory.create("Nele Deleu"));
        
                            for (var i = 0, len = persons.length; i < len; i++) {
                                persons[i].say();
                            }
                        }
                        run();
                

builder : constructs complex objects from simple objects.

examples

code:
                    <div class="spec">
                        <p id="ex-5-a"></p>
                        <p id="ex-5-b"></p>
                        <p id="ex-5-c"></p>
                    </div>
                    <script>
                        function Shop() {
                            this.construct = function (builder) {
                                builder.step1();
                                builder.step2();
                                return builder.get();
                            }
                        }
                        function CarBuilder() {
                            this.car = null;
                            this.step1 = function () {
                                this.car = new Car();
                            };
                            this.step2 = function () {
                                this.car.addParts();
                            };
                            this.get = function () {
                                return this.car;
                            };
                        }
                        function TruckBuilder() {
                            this.truck = null;
                            this.step1 = function () {
                                this.truck = new Truck();
                            };
                            this.step2 = function () {
                                this.truck.addParts();
                            };
                            this.get = function () {
                                return this.truck;
                            };
                        }
                        function Car() {
                            this.doors = 0;
                            this.addParts = function () {
                                this.doors = 4;
                            };
                            this.say = function () {
                                console.log("I am a " + this.doors + "-door car");
                                document.getElementById("ex-5-a").innerHTML = "I am a " + this.doors + "-door car";
                            };
                        }
                        function Truck() {
                            this.doors = 0;
                            this.addParts = function () {
                                this.doors = 2;
                            };
                            this.say = function () {
                                console.log("I am a " + this.doors + "-door truck");
                                document.getElementById("ex-5-b").innerHTML = "I am a " + this.doors + "-door truck";
                            };
                        }
                        function runit() {
                            var shop = new Shop();
                            var carBuilder = new CarBuilder();
                            var truckBuilder = new TruckBuilder();
                            var car = shop.construct(carBuilder);
                            var truck = shop.construct(truckBuilder);
        
                            car.say();
                            truck.say();
                        }
                        runit();
                    </script>
                

prototype : creates new objects from the existing objects.

examples

code:
                    <div class="spec">
                        <p id="ex-6"></p>
                        <p id="ex-6_a"></p>
                        <p id="ex-6_b"></p>
                    </div>
                    <script>
                        function CustomerPrototype(proto) {
                            this.proto = proto;
                            this.clone = function () {
                                var customer = new Customer();
        
                                customer.first = proto.first;
                                customer.last = proto.last;
                                customer.status = proto.status;
        
                                return customer;
                            };
                        }
                       function Customer(first, last, status) {
                            this.first = first;
                            this.last = last;
                            this.status = status;
                            this.say = function () {
                                console.log("name: " + this.first + " " + this.last +
                                    ", status: " + this.status);
                                document.getElementById("ex-6").innerHTML = "name: " + this.first + " " + this.last + ", status: " + this.status;
                            };
                        }
        
                        function run_that() {
                            var proto = new Customer("n/a", "n/a", "pending");
                            var prototype = new CustomerPrototype(proto);
        
                            var customer = prototype.clone();
                            customer.say();
                            }
                        run_that();
                    </script>
                

singleton : ensures that there's only one object created for a particular class.

examples

code:
                    <div class="spec">
                        <p id="ex-7"></p>
                    </div>
                    <script>
                        var Singleton = (function () {
                            var instance;
                            function createInstance() {
                                var object = new Object("I am the instance");
                                return object;
                            }
                            return {
                                getInstance: function () {
                                    if (!instance) {
                                        instance = createInstance();
                                    }
                                    return instance;
                                }
                            };
                        })();
        
                        function run_anyway() {
                            var instance1 = Singleton.getInstance();
                            var instance2 = Singleton.getInstance();
        
                            console.log("Same instance? " + (instance1 === instance2));
                            document.getElementById("ex-7").innerHTML = "Same instance? " + (instance1 === instance2);
                        }
                        run_anyway();
                    </script>
                

structural design patterns

top

These patterns concern class and object composition. They use inheritance to compose interfaces.

adapter : allows classes with incompatible interfaces to work together by wrapping their own interface around existing class.

examples

code:
                    <div class="spec">
                        <p id="ex-8"></p>
                        <p id="ex-8-a"></p>
                        <p id="ex-8-b"></p>
                    </div>
                    <script>
                        // old interface
                        function Shipping() {
                            this.request = function (zipStart, zipEnd, weight) {
                                // ...
                                return "$49.75";
                            }
                        }
                        // new interface
                        function AdvancedShipping() {
                            this.login = function (credentials) { /* ... */ };
                            this.setStart = function (start) { /* ... */ };
                            this.setDestination = function (destination) { /* ... */ };
                            this.calculate = function (weight) { return "$39.50"; };
                        }
                        // adapter interface
                        function ShippingAdapter(credentials) {
                            var shipping = new AdvancedShipping();
                            shipping.login(credentials);
                            return {
                                request: function (zipStart, zipEnd, weight) {
                                    shipping.setStart(zipStart);
                                    shipping.setDestination(zipEnd);
                                    return shipping.calculate(weight);
                                }
                            };
                        }
                        function run_b() {
                            var shipping = new Shipping();
                            var credentials = { token: "30a8-6ee1" };
                            var adapter = new ShippingAdapter(credentials);
                            // original shipping object and interface
                            var cost = shipping.request("78701", "10010", "2 lbs");
                            console.log("Old cost: " + cost);
                            document.getElementById("ex-8").innerHTML = "Old cost: " + cost;    
                            // new shipping object with adapted interface
                            cost = adapter.request("78701", "10010", "2 lbs");
                            console.log("New cost: " + cost);
                            document.getElementById("ex-8-a").innerHTML = "New cost: " + cost;   
                        }
                        run_b();
                

bridge : separates the abstraction from the implementation so that the two can vary independently.

examples

code:
                    <div class="spec">
                        <p id="ex-9"></p>
                        <p id="ex-9-a"></p>
                        <p id="ex-9-b"></p>
                        <p id="ex-9-c"></p>
                        <p id="ex-9-d"></p>
                        <p id="ex-9-e"></p>
                        <p id="ex-9-f"></p>
                        <p id="ex-9-g"></p>
                    </div>
                    <script>
                        // input devices
                        var Gestures = function (output) {
                            this.output = output;
                            this.tap = function () { this.output.click(); }
                            this.swipe = function () { this.output.move(); }
                            this.pan = function () { this.output.drag(); }
                            this.pinch = function () { this.output.zoom(); }
                        };
                        var Mouse = function (output) {
                            this.output = output;
                            this.click = function () { this.output.click(); }
                            this.move = function () { this.output.move(); }
                            this.down = function () { this.output.drag(); }
                            this.wheel = function () { this.output.zoom(); }
                        };
                        // output devices
                        var Screen = function () {
                            this.click = function () { console.log("Screen select"); 
                            document.getElementById("ex-9").innerHTML = "Screen select";}
                            this.move = function () { console.log("Screen move"); 
                            document.getElementById("ex-9-a").innerHTML = "Screen move";}
                            this.drag = function () { console.log("Screen drag");
                            document.getElementById("ex-9-b").innerHTML = "Screen drag";}
                            this.zoom = function () { console.log("Screen zoom in"); 
                            document.getElementById("ex-9-c").innerHTML = "Screen zoom in";}
                        };
                        var Audio = function () {
                            this.click = function () { console.log("Sound oink");
                            document.getElementById("ex-9-d").innerHTML = "Sound oink";}
                            this.move = function () { console.log("Sound waves");
                            document.getElementById("ex-9-e").innerHTML = "Sound waves";}
                            this.drag = function () { console.log("Sound screetch");
                            document.getElementById("ex-9-f").innerHTML = "Sound screetch;"}
                            this.zoom = function () { console.log("Sound volume up");
                            document.getElementById("ex-9-g").innerHTML = "Sound volume up";}
                        };
                        function run_for() {
                            var screen = new Screen();
                            var audio = new Audio();
                            var hand = new Gestures(screen);
                            var mouse = new Mouse(audio);
                            hand.tap();
                            hand.swipe();
                            hand.pinch();
                            mouse.click();
                            mouse.move();
                            mouse.wheel();
                        }
                        run_for();
                </pre>
            

composite : composes objects so that they can be manipulated as single objects.

examples

code:
                    <div class="spec">
                        <p id="ex-10"></p>
                        <p id="ex-10-a"></p>
                        <p id="ex-10-b"></p>
        
                    </div>
                    <script>
                       var Node = function (name) {
                            this.children = [];
                            this.name = name;
                        }
                        Node.prototype = {
                            add: function (child) {
                                this.children.push(child);
                            },
                            remove: function (child) {
                                var length = this.children.length;
                                for (var i = 0; i < length; i++) {
                                    if (this.children[i] === child) {
                                        this.children.splice(i, 1);
                                        return;
                                    }
                                }
                            },
                            getChild: function (i) {
                                return this.children[i];
                            },
                            hasChildren: function () {
                                return this.children.length > 0;
                            }
                        }
                        // recursively traverse a (sub)tree
                        function traverse(indent, node) {
                            console.log(Array(indent++).join("--") + node.name);
                            document.getElementById("ex-10").innerHTML += (Array(indent++).join("--") + node.name + '<br>');
                            for (var i = 0, len = node.children.length; i < len; i++) {
                                traverse(indent, node.getChild(i));
                            }
                        }
                        function run_now() {
                            var tree = new Node("root");
                            var left = new Node("left")
                            var right = new Node("right");
                            var leftleft = new Node("leftleft");
                            var leftright = new Node("leftright");
                            var rightleft = new Node("rightleft");
                            var rightright = new Node("rightright");
        
                            tree.add(left);
                            tree.add(right);
                            tree.remove(right);  // note: remove
                            tree.add(right);
        
                            left.add(leftleft);
                            left.add(leftright);
        
                            right.add(rightleft);
                            right.add(rightright);
        
                            traverse(1, tree);
                        }
                        run_now();
                    </script>
                

decorator : dynamically adds or overrides the behavior of an object.

examples

Codes:

                    <div class="spec">
                        <p id="ex-11"></p>
                        <p id="ex-11-a"></p>
                    </div>
                    <script>
                        var User = function (name) {
                            this.name = name;
                            this.say = function () {
                                console.log("User: " + this.name);
                                document.getElementById("ex-11").innerHTML = "User: " + this.name;
                            };
                        }
                        var DecoratedUser = function (user, street, city) {
                            this.user = user;
                            this.name = user.name;  // ensures interface stays the same
                            this.street = street;
                            this.city = city;
                            this.say = function () {
                                console.log("Decorated User: " + this.name + ", " +
                                    this.street + ", " + this.city);
                                document.getElementById("ex-11-a").innerHTML = "Decorated User: " + this.name + ", " +
                                    this.street + ", " + this.city;   
                            };
                        }
                        function run_This() {
                            var user = new User("Wendy");
                            user.say();
                            var decorated = new DecoratedUser(user, "Linkeroever", "Antwerpen");
                            decorated.say();
                        }
                        run_This();
                    </script>
                

facade : provides a simplified interface to complex code.

examples

Codes:

                    <div class="spec">
                        <p id="ex-12"></p>
                    </div>
                    <script>
                        var Mortgage = function (name) {
                            this.name = name;
                        }
                        Mortgage.prototype = {
                            applyFor: function (amount) {
                                // access multiple subsystems...
                                var result = "approved";
                                if (!new Bank().verify(this.name, amount)) {
                                    result = "denied";
                                } else if (!new Credit().get(this.name)) {
                                    result = "denied";
                                } else if (!new Background().check(this.name)) {
                                    result = "denied";
                                }
                                return this.name + " has been " + result +
                                    " for a " + amount + " mortgage";
                            }
                        }
                        var Bank = function () {
                            this.verify = function (name, amount) {
                                // complex logic ...
                                return true;
                            }
                       }
                        var Credit = function () {
                            this.get = function (name) {
                                // complex logic ...
                                return true;
                            }
                        }
                        var Background = function () {
                            this.check = function (name) {
                                // complex logic ...
                                return true;
                            }
                        }
                        function run_Me() {
                            var mortgage = new Mortgage("Michel Verschuren");
                            var result = mortgage.applyFor("$100,000");
                            console.log(result);
                            document.getElementById("ex-12").innerHTML = result;
                        }
                        run_Me();
                

flyweight : reduces the memory cost of creating similar objects.

examples

code:
                    <div class="spec">
                        <p id="ex-13"></p>
                        <p id="ex-13-a"></p>
                    </div>
                    <script>
                        function Flyweight(make, model, processor) {
                            this.make = make;
                            this.model = model;
                            this.processor = processor;
                        };
                        var FlyWeightFactory = (function () {
                            var flyweights = {};
                            return {
                                get: function (make, model, processor) {
                                    if (!flyweights[make + model]) {
                                        flyweights[make + model] = new Flyweight(make, model, processor);
                                    }
                                    return flyweights[make + model];
                                },
                                getCount: function () {
                                    var count = 0;
                                    for (var f in flyweights) count++;
                                    return count;
                                }
                            }
                        })();
                        function ComputerCollection() {
                            var computers = {};
                            var count = 0;
                            return {
                                add: function (make, model, processor, memory, tag) {
                                    computers[tag] =  new Computer(make, model, processor, memory, tag);
                                    count++;
                                },
                                get: function (tag) {
                                    return computers[tag];
                                },
                                getCount: function () {
                                    return count;
                                }
                            };
                        }
                        var Computer = function (make, model, processor, memory, tag) {
                            this.flyweight = FlyWeightFactory.get(make, model, processor);
                            this.memory = memory;
                            this.tag = tag;
                            this.getMake = function () {
                                return this.flyweight.make;
                            }
                            // ...
                        }
        
                        function run_F() {
                            var computers = new ComputerCollection();
        
                            computers.add("Dell", "Studio XPS", "Intel", "5G", "Y755P");
                            computers.add("Dell", "Studio XPS", "Intel", "6G", "X997T");
                            computers.add("Dell", "Studio XPS", "Intel", "2G", "U8U80");
                            computers.add("Dell", "Studio XPS", "Intel", "2G", "NT777");
                            computers.add("Dell", "Studio XPS", "Intel", "2G", "0J88A");
                            computers.add("HP", "Envy", "Intel", "4G", "CNU883701");
                            computers.add("HP", "Envy", "Intel", "2G", "TXU003283");
        
                            console.log("Computers: " + computers.getCount());
                            console.log("Flyweights: " + FlyWeightFactory.getCount());
                            document.getElementById("ex-13").innerHTML = "Computers: " + computers.getCount();
                            document.getElementById("ex-13-a").innerHTML = "FlyWeights: " + FlyWeightFactory.getCount();
                        }
        
                        run_F();
                    </script>
                </pre>
            

proxy : by using "proxy", a class can represent the functionality of another class.

examples

code:
                    <div class="spec">
                        <p id="ex-14"></p>
                        <p id="ex-14-a"></p>
                    </div>
                    <script>
                        function GeoCoder() {
                            this.getLatLng = function (address) {
                                if (address === "Amsterdam") {
                                    return "52.3700° N, 4.8900° E";
                                } else if (address === "London") {
                                    return "51.5171° N, 0.1062° W";
                                } else if (address === "Paris") {
                                    return "48.8742° N, 2.3470° E";
                                } else if (address === "Berlin") {
                                    return "52.5233° N, 13.4127° E";
                                } else {
                                    return "";
                                }
                            };
                            }
                        function GeoProxy() {
                            var geocoder = new GeoCoder();
                            var geocache = {};
        
                            return {
                                getLatLng: function (address) {
                                    if (!geocache[address]) {
                                        geocache[address] = geocoder.getLatLng(address);
                                    }
                                    console.log(address + ": " + geocache[address]);
                                    document.getElementById("ex-14").innerHTML += address + ": " 
                                    + geocache[address] + "<br>";
                                    return geocache[address];
                                },
                                getCount: function () {
                                    var count = 0;
                                    for (var code in geocache) { count++; }
                                    return count;
                                }
                            };
                        };
                        function run_IT() {
                            var geo = new GeoProxy();
                            // geolocation requests
                            geo.getLatLng("Paris");
                            geo.getLatLng("London");
                            geo.getLatLng("London");
                            geo.getLatLng("London");
                            geo.getLatLng("London");
                            geo.getLatLng("Amsterdam");
                            geo.getLatLng("Amsterdam");
                            geo.getLatLng("Amsterdam");
                            geo.getLatLng("Amsterdam");
                            geo.getLatLng("London");
                            geo.getLatLng("London");
                            console.log("\nCache size: " + geo.getCount());
                            document.getElementById("ex-14-a").innerHTML = "\nCache size: " 
                            + geo.getCount();
                        }
                        run_IT();
                    </script>
                

behavioral design patterns

top

Behavioral design patterns are specifically concerned with communication between objects, because they help to ensure the disparate parts have proper synchronization of informationM. Thus, it improves the flexibility of communication.

chain of responsibility : creates a chain of objects.

Starting from a point, it stops until it finds a certain condition.

examples

code:
                    <div class="spec">
                        <p id="ex-15"></p>
                        <p id="ex-15-a"></p>
                     </div>
                     <script>
                         var Request = function (amount) {
                             this.amount = amount;
                             console.log("Requested: $" + amount + "\n");
                             document.getElementById("ex-15").innerHTML = "Requested: $" + amount + "\n";
                         }
                         Request.prototype = {
                             get: function (bill) {
                                 var count = Math.floor(this.amount / bill);
                                 this.amount -= count * bill;
                                 console.log("Dispense " + count + " $" + bill + " bills");
                                 document.getElementById("ex-15-a").innerHTML += "Dispense " + count 
                                 + " $" + bill + " bills" + "<br>";
                                 return this;
                             }
                         }
                         function run_THAT() {
                             var request = new Request(378);
                             request.get(100).get(50).get(20).get(10).get(5).get(1);
                         }
                         run_THAT();
                     </script>
                

command : creates objects which encapsulate actions in objects.

examples

code:
                    <div class="spec">
                        <p id="ex-16"></p>
                        <p id="ex-16-a"></p>
                        <p id="ex-16-b"></p>
                    </div>
                    <script>
                        function add(x, y) { return x + y; }
                        function sub(x, y) { return x - y; }
                        function mul(x, y) { return x * y; }
                        function div(x, y) { return x / y; }
                        var Command = function (execute, undo, value) {
                            this.execute = execute;
                            this.undo = undo;
                            this.value = value;
                        }
                        var AddCommand = function (value) {
                            return new Command(add, sub, value);
                        };
                        var SubCommand = function (value) {
                            return new Command(sub, add, value);
                        };
                        var MulCommand = function (value) {
                            return new Command(mul, div, value);
                        };
                        var DivCommand = function (value) {
                            return new Command(div, mul, value);
                        };
                        var Calculator = function () {
                            var current = 0;
                            var commands = [];
        
                            function action(command) {
                                var name = command.execute.toString().substr(9, 3);
                                return name.charAt(0).toUpperCase() + name.slice(1);
                            }
                            return {
                                execute: function (command) {
                                    current = command.execute(current, command.value);
                                    commands.push(command);
                                    console.log(action(command) + ": " + command.value);
                                    document.getElementById("ex-16").innerHTML += action(command) 
                                    + ": " +command.value + "<br>";
                                },
        
                                undo: function () {
                                    var command = commands.pop();
                                    current = command.undo(current, command.value);
                                    console.log("Undo " + action(command) + ": " + command.value);
                                    document.getElementById("ex-16-a").innerHTML += "Undo " 
                                    + action(command) + ": " +command.value + "<br>";
                                },
                                getCurrentValue: function () {
                                    return current;
                                }
                            }
                        }
                        function run_FC() {
                            var calculator = new Calculator();
                            // issue commands
                            calculator.execute(new AddCommand(100));
                            calculator.execute(new SubCommand(24));
                            calculator.execute(new MulCommand(6));
                            calculator.execute(new DivCommand(2));
                            // reverse last two commands
                            calculator.undo();
                            calculator.undo();
                            console.log("\nValue: " + calculator.getCurrentValue());
                            document.getElementById("ex-16-b").innerHTML = "\nValue: " + calculator.getCurrentValue();
                        }
                        run_FC();    
                    </script>
                

iterator : accesses the elements of an object without exposing its underlying representation.

examples

code:
                    <div class="spec">
                        <p id="ex-17"></p>
                        <p id="ex-17-a"></p>
                        <p id="ex-17-b"></p>
                    </div>
                    <script>
                        var Iterator = function (items) {
                            this.index = 0;
                            this.items = items;
                        }
                        Iterator.prototype = {
                            first: function () {
                                this.reset();
                                return this.next();
                            },
                            next: function () {
                                return this.items[this.index++];
                            },
                            hasNext: function () {
                                return this.index <= this.items.length;
                            },
                            reset: function () {
                                this.index = 0;
                            },
                            each: function (callback) {
                                for (var item = this.first(); this.hasNext(); item = this.next()) {
                                    callback(item);
                                }
                            }
                        }
                        function run_ALL() {
                            var items = ["one", 2, "circle", true, "Applepie"];
                            var iter = new Iterator(items);
                            // using for loop
                            for (var item = iter.first(); iter.hasNext(); item = iter.next()) {
                                console.log(item);
                                document.getElementById("ex-17").innerHTML += item + "<br>";
                            }
                            console.log("");
                            document.getElementById("ex-17-a").innerHTML = "";
                            // using Iterator's each method
                            iter.each(function (item) {
                                console.log(item);
                                document.getElementById("ex-17-b").innerHTML += item + "<br>";
                            });
                        }
                        run_ALL();
                    </script>
                

mediator : adds a third-party object to control the interaction between two objects.

It allows loose coupling between classes by being the only class that has detailed knowledge of their methods.

examples

code:
                    <div class="spec">
                        <p id="ex-18"></p>
                        <p id="ex-18-a"></p>
                    </div>
                    <script>
                        var Participant = function (name) {
                                this.name = name;
                                this.chatroom = null;
                            };
                            Participant.prototype = {
                                send: function (message, to) {
                                    this.chatroom.send(message, this, to);
                                },
                                receive: function (message, from) {
                                    console.log(from.name + " to " + this.name + ": " + message);
                                    document.getElementById("ex-18").innerHTML += from.name + " to " 
                                    + this.name + ": " + message + "<br>";
                                }
                            };
                            var Chatroom = function () {
                                var participants = {};
                                return {
                                    register: function (participant) {
                                        participants[participant.name] = participant;
                                        participant.chatroom = this;
                                    },
                                    send: function (message, from, to) {
                                        if (to) {                      // single message
                                            to.receive(message, from);
                                        } else {                       // broadcast message
                                            for (key in participants) {
                                                if (participants[key] !== from) {
                                                    participants[key].receive(message, from);
                                                }
                                            }
                                        }
                                    }
                                };
                            };
                            function chat() {
                                var yoko = new Participant("Yoko");
                                var john = new Participant("John");
                                var paul = new Participant("Paul");
                                var ringo = new Participant("Ringo");
            
                                var chatroom = new Chatroom();
                                chatroom.register(yoko);
                                chatroom.register(john);
                                chatroom.register(paul);
                                chatroom.register(ringo);
            
                                yoko.send("All you need is love.");
                                yoko.send("I love you John.");
                                john.send("Hey, no need to broadcast", yoko);
                                paul.send("Ha, I heard that!");
                                ringo.send("Paul, what do you think?", paul);
                            }
                            chat();
                    </script>
                

memento : restores an object to its previous state.

examples

code
                    <div class="spec">
                        <p id="ex-19"></p>
                        <p id="ex-19-a"></p>
                    </div>
                    <script>
                        var Person = function (name, street, city, state) {
                            this.name = name;
                            this.street = street;
                            this.city = city;
                            this.state = state;
                        }
                        Person.prototype = {
                            hydrate: function () {
                                var memento = JSON.stringify(this);
                                return memento;
                            },
                            dehydrate: function (memento) {
                                var m = JSON.parse(memento);
                                this.name = m.name;
                                this.street = m.street;
                                this.city = m.city;
                                this.state = m.state;
                            }
                        }
                        var CareTaker = function () {
                            this.mementos = {};
                            this.add = function (key, memento) {
                                this.mementos[key] = memento;
                            },
                                this.get = function (key) {
                                    return this.mementos[key];
                                }
                        }
                        function validate() {
                            var mike = new Person("Derk Winters", "66 Rubenslei", "Antwerpen", "Belgie");
                            var john = new Person("Chris Teunissen", "Achtergracht", "Amsterdam", "Nederland");
                            var caretaker = new CareTaker();
                            // save state
                            caretaker.add(1, mike.hydrate());
                            caretaker.add(2, john.hydrate());
                            // mess up their names
                            mike.name = "King Kong";
                            john.name = "Superman";
                            // restore original state
                            mike.dehydrate(caretaker.get(1));
                            john.dehydrate(caretaker.get(2));
                            console.log(mike.name);
                            console.log(john.name);
                            document.getElementById("ex-19").innerHTML = mike.name;
                            document.getElementById("ex-19-a").innerHTML = john.name;
                        }
                        validate();
                    </script>
                </pre>
            

observer : allows a number of observer objects to see an event.

examples

code:
                    <div class="spec">
                        <p id="ex-20"></p>
                    </div>
                    <script>
                        function Click() {
                            this.handlers = [];  // observers
                        }
                        Click.prototype = {
                            subscribe: function (fn) {
                                this.handlers.push(fn);
                            },
                            unsubscribe: function (fn) {
                                this.handlers = this.handlers.filter(
                                    function (item) {
                                        if (item !== fn) {
                                            return item;
                                        }
                                    }
                                );
                            },
                            fire: function (o, thisObj) {
                                var scope = thisObj || window;
                                this.handlers.forEach(function (item) {
                                    item.call(scope, o);
                                });
                            }
                        }
                        function handle() {
                            var clickHandler = function (item) {
                                console.log("fired: " + item);
                                document.getElementById("ex-20").innerHTML += "fired: " + item + "<br>";
                        
                            };
                            var click = new Click();
        
                            click.subscribe(clickHandler);
                            click.fire('event #1');
                            click.unsubscribe(clickHandler);
                            click.fire('event #2');
                            click.subscribe(clickHandler);
                            click.fire('event #3');
                        }
                        handle();
        
                    </script>
                

visitor : adds operations to objects without having to modify them.

examples

code:
                    <div class="spec">
                        <p id="ex-21"></p>
                    </div>
                    <script>
                        var Employee = function (name, salary, vacation) {
                            var self = this;
                            this.accept = function (visitor) {
                                visitor.visit(self);
                            };
                            this.getName = function () {
                                return name;
                            };
                            this.getSalary = function () {
                                return salary;
                            };
                            this.setSalary = function (sal) {
                                salary = sal;
                            };
                            this.getVacation = function () {
                                return vacation;
                            };
                            this.setVacation = function (vac) {
                                vacation = vac;
                            };
                        };
                        var ExtraSalary = function () {
                            this.visit = function (emp) {
                                emp.setSalary(emp.getSalary() * 1.1);
                            };
                        };
                        var ExtraVacation = function () {
                            this.visit = function (emp) {
                                emp.setVacation(emp.getVacation() + 2);
                            };
                        };
        
                        function merit() {
                            var employees = [
                                new Employee("Johan", 10000, 10),
                                new Employee("Mia", 20000, 21),
                                new Employee("Jos", 250000, 51)
                            ];
                            var visitorSalary = new ExtraSalary();
                            var visitorVacation = new ExtraVacation();
                            for (var i = 0, len = employees.length; i < len; i++) {
                                var emp = employees[i];
        
                                emp.accept(visitorSalary);
                                emp.accept(visitorVacation);
                                console.log(emp.getName() + ": $" + emp.getSalary() +
                                    " and " + emp.getVacation() + " vacation days");
                                document.getElementById("ex-21").innerHTML += emp.getName() + ": $" + emp.getSalary() +
                                    " and " + emp.getVacation() + " vacation days" + "<br>";
                            }
                        }
                        merit();
                    </script>
                

strategy : allows one of the algorithms to be selected in certain situations.

examples

code:
                    <div class="spec">
                        <p id="ex-22"></p>
                        <p id="ex-22-a"></p>
                        <p id="ex-22-b"></p>
                    </div>
                    <script>
                        var Shipping = function () {
                            this.company = "";
                        };
                        Shipping.prototype = {
                            setStrategy: function (company) {
                                this.company = company;
                            },
                            calculate: function (package) {
                                return this.company.calculate(package);
                            }
                        };
                        var UPS = function () {
                            this.calculate = function (package) {
                                // calculations...
                                return "$45.95";
                            }
                        };
                        var USPS = function () {
                            this.calculate = function (package) {
                                // calculations...
                                return "$39.40";
                            }
                        };
                        var Fedex = function () {
                            this.calculate = function (package) {
                                // calculations...
                                return "$43.20";
                            }
                        };
                        function make_it() {
                            var package = { from: "76712", to: "10012", weigth: "lkg" };
                            // the 3 strategies
                            var ups = new UPS();
                            var usps = new USPS();
                            var fedex = new Fedex();
                            var shipping = new Shipping();
                            shipping.setStrategy(ups);
                            console.log("UPS Strategy: " + shipping.calculate(package));
                            document.getElementById("ex-22").innerHTML = "UPS Strategy: " + shipping.calculate(package);
                            shipping.setStrategy(usps);
                            console.log("USPS Strategy: " + shipping.calculate(package));
                            document.getElementById("ex-22-a").innerHTML = "UPS Strategy: " + shipping.calculate(package);
                            shipping.setStrategy(fedex);
                            console.log("Fedex Strategy: " + shipping.calculate(package));
                            document.getElementById("ex-22-b").innerHTML = "Fedex Strategy: " + shipping.calculate(package);
                        }
                        make_it();
                    </script>
                

state : alters the behavior of an object when its internal state changes.

examples

code:
                    <div class="spec">
                        <p id="ex-23"></p>
                    </div>
                    <script>
                        var TrafficLight = function () {
                            var count = 0;
                            var currentState = new Red(this);
                            this.change = function (state) {
                                // limits number of changes
                                if (count++ >= 10) return;
                                currentState = state;
                                currentState.go();
                            };
                            this.start = function () {
                                currentState.go();
                            };
                        }
                        var Red = function (light) {
                            this.light = light;
                            this.go = function () {
                                console.log("Red --> for 1 minute");
                                document.getElementById("ex-23").innerHTML += "Red --> for 1 minute" + "<br>"; 
                                light.change(new Green(light));
                            }
                        };
                        var Yellow = function (light) {
                            this.light = light;
        
                            this.go = function () {
                                console.log("Yellow --> for 10 seconds");
                                document.getElementById("ex-23").innerHTML += "Yellow --> for 10 seconds" + "<br>";
                                light.change(new Red(light));
                            }
                        };
                        var Green = function (light) {
                            this.light = light;
                            this.go = function () {
                                console.log("Green --> for 1 minute");
                                document.getElementById("ex-23").innerHTML += "Green --> for 1 minute" + "<br>";
                                light.change(new Yellow(light));
                            }
                        };
                        function run_light() {
                            var light = new TrafficLight();
                            light.start();
                        }
                        run_light();
                    </script>
                

template method : defines the skeleton of an algorithm as an abstract class, that how should it be performed.

examples

code:
                    <div class="spec">
                        <p id="ex-24"></p>
                    </div>
                    <script>
                        var datastore = {
                            process: function () {
                                this.connect();
                                this.select();
                                this.disconnect();
                                return true;
                            }
                        };
                        function inherit(proto) {
                            var F = function () { };
                            F.prototype = proto;
                            return new F();
                        }
                        function run_as() {
                            var mySql = inherit(datastore);
                            // implement template steps
                            mySql.connect = function () {
                                console.log("MySQL: connect step");
                                document.getElementById("ex-24").innerHTML += "MySQL: connect step" + "<br>";
                            };
        
                            mySql.select = function () {
                                console.log("MySQL: select step");
                                document.getElementById("ex-24").innerHTML += "MySQL: select step" + "<br>" ;
                            };
        
                            mySql.disconnect = function () {
                                console.log("MySQL: disconnect step");
                                document.getElementById("ex-24").innerHTML += "MySQL: disconnect step" + "<br>";
                            };
                            mySql.process();
                        }
                        run_as();
                    </script>