読者です 読者をやめる 読者になる 読者になる

JSでIteratorパターンを実現

javascriptIteratorパターンを実現する

javascriptとは

 クライアントサイドの処理において必要不可欠なもの。

 javascriptが扱うものは全てオブジェクトであり、関数型言語であるという特徴がある。そのため、関数もオブジェクトとして存在し、変数のように扱うことができる。また、クロージャによりオブジェクトの外の変数を参照する機能がある。

 

デザインパターンとは

 プログラム設計時に起こる典型的な問題とそれに対する解決策を整理し、再利用できるようにまとめたもの。1995年に出版された書籍「デザインパターン」の中で23のパターンが解説されたのをきっかけに広まった。

 

javascriptデザインパターン実現

 jsでデザインパターンを実現するには、jsでオブジェクト指向プログラミングを行えばよい。javaに慣れている人にとってはクラスがないのにオブジェクト指向をどう行うのかと思うかもしれないが、jsではオブジェクトのプロパティとしてオブジェクト(関数、変数)を指定することができこれを継承することでオブジェクト指向を実現していく。そのためには以下のコードで、継承もとのプロパティをコピーした上で新規のプロパティを上書きするsubClass化関数を使用する。

・subClass.js

(function() {
  var initializing = false,
      superPattern =  // Determine if functions can be serialized
        /xyz/.test(function() { xyz; }) ? /\b_super\b/ : /.*/;       //#1

  // Creates a new Class that inherits from this class
  Object.subClass = function(properties) {                           //#2
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;                                              //#3
    var proto = new this();                                           //#3
    initializing = false;                                             //#3

    // Copy the properties over onto the new prototype
    for (var name in properties) {                                    //#4
      // Check if we're overwriting an existing function
      proto[name] = typeof properties[name] == "function" &&
                    typeof _super[name] == "function" &&
                    superPattern.test(properties[name]) ?
          (function(name, fn) {                                        //#5
            return function() {
              var tmp = this._super;

              // Add a new ._super() method that is the same method
              // but on the super-class
              this._super = _super[name];

              // The method only need to be bound temporarily, so we
              // remove it when we're done executing
              var ret = fn.apply(this, arguments);
              this._super = tmp;

              return ret;
            };
          })(name, properties[name]) :
          properties[name];
    }

    // The dummy class constructor
    function Class() {                                                   //#6
      // All construction is actually done in the init method
      if (!initializing && this.init)
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = proto;                                             //#7

    // Enforce the constructor to be what we expect
    Class.constructor = Class;                                           //#8

    // And make this class extendable
    Class.subClass = arguments.callee;                                   //#9

    return Class;
  };
})();

 

Iteratorパターン

 Iteratorパターンとは、コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部試用に依存しない反復しの提供を行う。サンプルコードではbookShelf.hasNext()によりコンテナオブジェクトの列挙を行っている。列挙する手段を独立させることにより、コンテナに手が加わっても列挙用クラスに手を加えなくてよくなるという利点がある。

 

以下がjsでのIteratorパターン実装になる

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
    <title>iterator</title>
  </head>
  <body>
      <script type="text/javascript" src="subclass.js"></script>
    <script type="text/javascript">
   
    var Book = Object.subClass({
        name:"aa",
        create:"create",
        getName:function(){
            return this.name;
        },
        setName:function(name){
            this.name = name;
        }
    });
    
    var BookCreate = Book.subClass({
        getName:function(){
            return this.name + this.create;
        }
    });
    
    var BookShelf = Object.subClass({
        index:0,
        lastIndex:0,
        Books:[],
        Book:"",
        appendBook:function(book){
            this.Books[this.lastIndex] = book;
            this.lastIndex++;
        },
        get:function(){
            this.Book = this.Books[this.index];
            this.index++;
            return this.Book.getName();
        },
        hasNext:function(){
            var ret = false;
            if(this.index<this.lastIndex){
                ret = true;
            }
            return ret;
        }
    });
    var bookShelf = new BookShelf();
    var book1 = new Book();
    book1.setName("testttt");
    var book2 = new BookCreate();
    bookShelf.appendBook(book1);
    bookShelf.appendBook(book2);
    while(bookShelf.hasNext()){
        answer(bookShelf.get());
    }


      function answer( desc) {
        var resultsList = document.getElementById("results");
        if (!resultsList) {
          resultsList = document.createElement('ul');
          document.getElementsByTagName('body')[0].appendChild(resultsList);
          resultsList.setAttribute('id','results');
        }
        var li = document.createElement("li");
        li.className =  "pass";
        li.appendChild(document.createTextNode(desc));
        resultsList.appendChild(li);
      }
      
    </script>
  </body>
</html>

 

bookShelfのgetメソッドで、現在のインデックスのBookのgetNameメソッドが実行できていることを確認できる。