Following on from the previous article on creating patterns, this article covers behavioral and structural patterns.

Behavior patterns

Observer model

Javascript event and time handlers are a representation of the observer pattern, another name for which is the Publish/subscriber pattern

When you create an event handler, such as an event that fires, that executes a function, this is observer mode. The Observer mode is a subscription model that allows you to assign an object to listen for events.

Here’s an example:

The Click object represents a topic, and the ClickHandler represents an observer subscribed to that topic.

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) {returnitem; }}); },notify: function (o, thisObj) {
        var scope = thisObj || window;
        this.handlers.forEach(function (item) { item.call(scope, o); }); }}function run() {

    var clickHandler = function (item) {
        console.log("notify: " + item);
    };
    var click = new Click();

    click.subscribe(clickHandler);
    click.notify('event #1');
    click.unsubscribe(clickHandler);
    click.notify('event #2');
    click.subscribe(clickHandler);
    click.notify('event #3');
}

// Print the result
// notify: event #1
// notify: event #3
Copy the code

Structure mode

Adapter mode

The adapter pattern is an abstraction layer or intermediate from one interface to another, typically converting API interface returns into JSON objects in a specified format by converting raw API data (JSON, XML, and so on) into usable javascript objects.

The following example shows an online shopping cart in which a shipping object is used to calculate expenses. The old shipping object needs to be replaced by a new AdvancedShipping object that is more secure and provides a better way to calculate expenses.

However, the API provided by the new AdvancedShipping does not match the original shipping object. In this case, AdvancedShipping allows the old shipping interface parameters to be supplied to the new AdvancedShipping object. Allows client programs to allow new AdvancedShipping interfaces without any API changes.

// 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);
            returnshipping.calculate(weight); }}; }function run() {

    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);

    // new shipping object with adapted interface
    cost = adapter.request("78701"."10010"."2 lbs");

    console.log("New cost: " + cost);
}
Copy the code