Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A running example or working demo of Interface pattern in JavaScript

I am reading the "pro javascript design patterns" book and finding little difficulty in understanding the "Interface" pattern given in the book chapter 2 as there isn't a complete code example demonstrating the use of this pattern.

I am looking for some help understanding this pattern with some running code example may be on jsfiddle etc.

This pattern is explained in the book pages 14 - 22, main point I am not understanding is where and how "addForm" method is called. OR if somebody can complete the ResultFormatter example with some test data and object this will really be very helpful in understanding the pattern.

Code for the book "Pro Javascript Design Patterns" can be downloaded from http://jsdesignpatterns.com/ and this is Chapter 2.

Thanks for the help !!

like image 439
Anmol Saraf Avatar asked Oct 24 '12 00:10

Anmol Saraf


People also ask

What is design pattern in JavaScript with example?

Design patterns are reusable solutions to commonly occurring problems in software design. They are proven solutions, easily reusable and expressive. They lower the size of your codebase, prevent future refactoring, and make your code easier to understand by other developers.

How do interfaces work in JavaScript?

Interfaces are capable of describing the wide range of shapes that JavaScript objects can take. In addition to describing an object with properties, interfaces are also capable of describing function types. To describe a function type with an interface, we give the interface a call signature.

How do you write an interface in JavaScript?

The easiest way to see how interfaces work is to start with a simple example: function printLabel(labelledObj: { label: string }) { console. log(labelledObj. label); } let myObj = {size: 10, label: "Size 10 Object"}; printLabel(myObj);

What are design patterns example and explanation?

Design patterns provide a standard terminology and are specific to particular scenario. For example, a singleton design pattern signifies use of single object so all developers familiar with single design pattern will make use of single object and they can tell each other that program is following a singleton pattern.


2 Answers

ES6 has added syntactical sugar to the language. Below is the ES6 implementation of the same example.

class Interface {
    constructor(name, methods) {
        if (arguments.length < 2) {
            throw new Error('An Interface expects atleast 2 arguments ' + arguments.length
                + ' arguments passed')
            
        }
        this.name = name
        this.methods = []
        methods.forEach(method => {
            if (typeof method !== 'string') {
                throw new Error('Interface expects all the method names to be passed as as a string ' +
                    method + ' is a ' + typeof method)
            }
            this.methods.push(method)
        }, this);
    }

    static ensureImplements(object) {
        if(arguments.length < 2) {
            throw new Error("Function Interface.ensureImplements called with " +
                arguments.length + "arguments, but expected at least 2.")
        }

        for (let i = 1, len=arguments.length; i < len; i++) {
            const interf = arguments[i]
            if(interf.constructor !== Interface) {
                throw new Error('Function expects arguments two or above to be instaces of Interface' )
            }

            for(let j = 0, methodsLen = interf.methods.length; j < methodsLen; j++) {
                const method = interf.methods[j]
                if(!object[method] || !typeof object[method] === 'function') {
                    throw new Error('Does not implement the method the interface' + interf.name + 'Interface.Method '
                    + method + ' not found')
                }
            }
        }
    }
}

const DynamicMap = new Interface('DynamicMap', ['centerOnPoint', 'zoom', 'draw'])

class Map {
    constructor() {
        Interface.ensureImplements(this, DynamicMap)
    }
    centerOnPoint() {
        console.log('Moving to center')
    }
    zoom() {
        console.log('Zooming in')
    }

    draw() {
        console.log('Drawing map')
    }
}

const mapInstance = new Map()

Try playing around with the code by removing the methods in the Map class. Hope it explains better to the people coming from oops background

like image 82
Minkesh Jain Avatar answered Sep 20 '22 13:09

Minkesh Jain


Completed the book example and here is the working jsfiddle, -

var Interface = function(name, methods) {
    if (arguments.length != 2) {
        throw new Error("Interface constructor called with " + arguments.length + "arguments, but expected exactly 2.");
    }

    this.name = name;
    this.methods = [];

    for (var i = 0, len = methods.length; i < len; i++) {
        if (typeof methods[i] !== 'string') {
            throw new Error("Interface constructor expects method names to be " + "passed in as a string.");
        }

        this.methods.push(methods[i]);
    }
};

// Static class method.
Interface.ensureImplements = function(object) {
    if (arguments.length < 2) {
        throw new Error("Function Interface.ensureImplements called with " + arguments.length + "arguments, but expected at least 2.");
    }

    for (var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];

        if (interface.constructor !== Interface) {
            throw new Error("Function Interface.ensureImplements expects arguments" + "two and above to be instances of Interface.");
        }

        for (var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
            var method = interface.methods[j];

            if (!object[method] || typeof object[method] !== 'function') {
                throw new Error("Function Interface.ensureImplements: object " + "does not implement the " + interface.name + " interface. Method " + method + " was not found.");
            }
        }
    }
};

function Map() {}

Map.prototype.centerOnPoint = function(x,y) {
    alert('center=> x: ' + x + ', y: ' + y);
};

Map.prototype.zoom = function(x){
    alert('zoom : ' + x);
}

Map.prototype.draw = function(){
    alert('draw');
};

var map = new Map();
var DynamicMap = new Interface('DynamicMap', ['centerOnPoint', 'zoom', 'draw']);

function displayRoute(mapInstance) {
    Interface.ensureImplements(mapInstance, DynamicMap);
    mapInstance.centerOnPoint(12, 34);
    mapInstance.zoom(5);
    mapInstance.draw();
}

displayRoute(map);​
like image 36
Anmol Saraf Avatar answered Sep 19 '22 13:09

Anmol Saraf