10

私は「プロjavascriptデザインパターン」の本を読んでいますが、このパターンの使用法を示す完全なコード例がないため、本の第2章に記載されている「インターフェイス」パターンを理解するのはほとんど困難ではありません。

jsfiddleなどで実行されているコード例を使用して、このパターンを理解するためのヘルプを探しています。

このパターンは、本の14〜22ページで説明されています。私が理解していない主なポイントは、「addForm」メソッドがどこでどのように呼び出されるかです。または、誰かがResultFormatterの例をいくつかのテストデータとオブジェクトで完成させることができれば、これはパターンを理解するのに非常に役立ちます。

「ProJavascriptDesignPatterns」という本のコードは、http://jsdesignpatterns.com/からダウンロードできます。これは第2章です。

助けてくれてありがとう !!

4

3 に答える 3

9

パターンがさまざまな方法で実装されているのを見てきましたが、アイデアは単純です。

  1. いくつかの関数の名前を指定するだけのクラス(インターフェース)があります。(実際のインターフェースがインスタンス化するInterfaceというクラスが必要な場合があります。これにより、インターフェースのタイプはInterfaceになります)
  2. 次に、そのようなインターフェイスを実装する他のクラスがあります。つまり、この2番目のクラスには、インターフェイスで指定された少なくともすべての関数が必要です。
  3. 最後に、インターフェイスを実装するオブジェクトを受け取ることを期待する他の関数がどこかにあります。言及したサンプルコードでは、この関数はaddFormであり、「Composite」および「FormItem」インターフェイスを実装するオブジェクトを想定しています。
  4. 次に、この関数は、予期するインターフェイスのすべてのメソッドをループし、渡されたオブジェクトにもそれらのメソッドがあることを確認します。いずれかのインターフェイスのメソッドが関数に渡されたオブジェクトに見つからない場合、オブジェクトはインターフェイスを実装していないと判断し、例外をスローします。

オーバーヘッドが関係するため、このパターンは実用的ではないと感じる人もいるかもしれませんが、Javascriptにはインターフェースのネイティブサポートがないため、これはそれほど悪い解決策ではありません。また、Javascriptで小さなプロジェクトにインターフェースを使用するのはやり過ぎだと感じる人もいるかもしれません。

var Interface = function(name, methods) {
    this.name = name;
    this.methods = [];

    if (methods.constructor == Array)
        this.methods = methods;
    else if (methods.constructor == String)
        this.methods[0] = methods;
    else
        throw new Error("Interface must define methods as a String or an Array of Strings");
};

var InterfaceHelper  = {
    ensureImplements : function(obj, interfaces) {
       // If interfaces is not an array, assume it's a function pointer
       var toImplement = interfaces.constructor == Array ? interfaces : [interfaces];
       var interface;

       // For every interface that obj must implement:
       for (var i = 0, len = toImplement.length; i < len; i++) {
          interface = toImplement[i];

          // Make sure it indeed is an interface
          if (interface.constructor != Interface)
             throw new Error("Object trying to implement a non-interface. "
             + interface.name + " is not an Interface.");

          // Make sure obj has all of the methods described in the interface
          for (var j = 0, interfaceLen = interface.methods.length; j < interfaceLen; j++)
             if (!obj[interface.methods[j]])
                throw new Error("Interface method not implemented. " 
                + interface.name + " defines method " + interface.methods[j]);
       }

       return true;
    }
};

var Drawable = new Interface("Drawable", ["onDraw"]);

var Surface = function() {
   this.implements = ["Drawable"];

   this.onDraw = function() {
      console.log("Surface Drawing");
   };
};

使用法

var myDrawableSurface = new Surface();

// Returns true
InterfaceHelper.ensureImplements(myDrawableSurface, Drawable);

// Returns false (Error thrown)
InterfaceHelper.ensureImplements(myDrawableSurface, Array);
于 2012-11-01T14:30:11.353 に答える
5

本の例を完成させました。これが動作中の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);​
于 2012-11-01T19:11:16.110 に答える
2

ES6は、言語に構文糖衣構文を追加しました。以下は、同じ例のES6実装です。

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

Mapクラス内のメソッドを削除して、コードを試してみてください。おっとの背景から来る人々にそれがよりよく説明することを願っています

于 2017-08-09T22:05:43.227 に答える