本を読む筆記の-javascript設計モード-インターフェイス、パッケージとチェーン呼び出し

18981 ワード

javascriptは設計モードを採用しています.主に次の3つの原因があります.
  • の維持可能性:設計モードはモジュール間の結合の程度を低減するのに役立つ.これはコードを再構築し、異なるモジュールを交換することを容易にし、プログラマが大型プロジェクトで協力しやすくします.
  • コミュニケーション:設計モードは、異なるタイプのオブジェクトを処理するために共通の用語のセットを提供する.プログラマは自分のシステムの働き方を簡潔に説明することができます.
  • パフォーマンス:いくつかの最適化された性能を採用することで、プログラムの実行効率を大幅に向上させることができます.例えば、享元モードや代理モードなどの
  • また、設計モードを濫用することは、いくつかの結果をもたらします.
  • 複雑性:コードが複雑になり、新米は分かりにくいです.
  • 性能:多くの設計モードはコードの性能を多かれ少なかれ下げることができます.
    実現は容易で、合理的に使うのは難しい.一つの提案は、できるだけ最適なものを選んでください.しかし、あまりにも性能を犠牲にしないでください.
    インターフェース:インターフェースは、これらの方法の意味を示しているが、このオブジェクトがどのような方法を持っているかを説明するための手段であるが、実装は規定されていない.
    Javascriptでインターフェースを真似します.
    一:インターフェースを注釈で説明する
    /*
    
     interface Composite{
    
     function add(child);
    
     function remove(child);
    
     function getChild(index);
    
     }
    
     interface FormItem{
    
     function save();
    
     }
    
     */
    
    
    
    var CompositeForm = function(id,method,action){
    
    
    
    }
    
    CompositeForm.prototype.add = function(){
    
    
    
    }
    
    CompositeForm.prototype.remove = function(){
    
    
    
    }
    
    CompositeForm.prototype.getChild = function(){
    
    
    
    }
    
    CompositeForm.prototype.save = function(){
    
    
    
    }
    このような模倣は文書段階にとどまっているだけです.正しい方法が実現されているかどうかをチェックしていないし、間違ったことを投げ出すこともなく、完全に自覚に頼る.
    二:属性で模擬インターフェースを確認する:
    /*
    
     interface Composite{
    
     function add(child);
    
     function remove(child);
    
     function getChild(index);
    
     }
    
     interface FormItem{
    
     function save();
    
     }
    
     */
    
    
    
    var CompositeForm = function(id,method,action){
    
        this.implementsInterfaces = ['Composite','FormItem'];
    
    
    
    }
    
    
    
    function addForm(formInstance){
    
        if(!implements(formInstance,'Composite','FormItem'){
    
            throw new Error("Object does not implement a required interface.");
    
        })
    
    }
    
    
    
    function implements(object){
    
        for(var i=1;i<arguments.length;i++){
    
            var interfaceName = argument[i];
    
            var interfaceFound = false;
    
            for(var j=0;j<object.implementsInterfaces.length;j++){
    
                if(object.implementsInterfaces[j]==interfaceName){
    
                    interfaceFound = true;
    
                    break;
    
                }
    
            }
    
            //       
    
            if(!interfaceFound){
    
                return false;
    
            }
    
        }
    
        //        
    
        return true;
    
    }
    ここで、CompsiteFormは、自分がCompsite'を実現したと宣言しました.'FormItem'という二つのインターフェースは、この二つのインターフェースの名前を一つのオブジェクトの配列に加えることで、明示的な声明は自分のサポートするインターフェースです.
    いずれかのパラメータが特定のタイプの関数に属しているということは、この属性を検査し、実現方法が見つからない場合には、例外を投げます.
    三、アヒルの形の弁別の模擬インターフェース
    オブジェクト実装の方法セットを、あるクラスの唯一の基準であるかどうかを判断する方法として、この方法の背後にある観点は簡単である.オブジェクトがインターフェース定義の方法と同名である場合、このインターフェースが実現されたと考えられる.
    Interface類の定義
    /*
    
     *       
    
     */
    
    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 - 1; 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]);
    
        };
    
    };
    
    
    
    /*
    
     *  Interface        
    
     */
    
    
    
    Interface.ensureImplements = function(obj){
    
        if(arguments.length<2){
    
            throw new Error("Function Interface.ensureImplements called with " +
    
                arguments.length  + "arguments, but expected at least 2.");
    
        };
    
    
    
        for (var i = 0,len = methods.length - 1; 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 extend(subClass,superClass){
    
        var F = function(){};
    
        F.prototype = superClass.prototype;
    
        subClass.prototype = new F();
    
        subClass.peototype.constructor = subClass;
    
    
    
        subClass.superclass = superClass.prototype;
    
        if(superClass.prototype.constructor == Object.prototype.constructor){
    
            superClass.prototype.constructor = superClass;
    
        }
    
    }
    スーパークラスは、サブクラスとクラス間の結合を弱体化するために使用されます.同時に超種類のconstructorが正しく設定されていることを確認します.
    原型継承の実現は、実際にはコピー継承であり、実現は以下の通りです.
    function clone(object){
    
        function F(){};
    
        F.prototype = object;
    
        return new F;
    
    }
    実際に戻ってきたのは、与えられたオブジェクトを元にした空のオブジェクトです.
    添加元の実現.厳密な継承を必要としない重用の方法があります.一つの関数を複数のクラスに使用する場合、拡張された方法でこの関数を共有することができます.まず、さまざまな共通の方法を含むクラスを作成し、他のクラスを拡張します.このようなパッケージは、一般的な方法を含むクラスをドーパントといいます.
    添加元類の実現方法:
    function augment(receivingClass,givingClass){
    
        //if has the third arg
    
        if(arguments.length[2]){
    
            for(var i=2,len = arguments.length;i<len;i++){
    
                receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
    
            }
    
        }else{
    
            for(methodName in givingClass.prototype){
    
                if(!receivingClass.prototype[methodName]){
    
                    receivingClass.prototype[methodName] = givingClass.prototype[methodName];
    
                }
    
            }
    
        }
    
    }
    パッケージ
    パッケージとは、オブジェクト内部のデータ表現の形式と実装の詳細を非表示にすることです.パッケージされたオブジェクトにアクセスするには、定義された操作しかできません.
    javascriptでは、キーワードがなく、クローズドの概念を使ってプライベートな属性と方法を作成するしかないです.
    javascriptオブジェクトを作成したい基本パターンは3つあります.
    ポータルが大きくオープンし、プライベート方法と属性を下線で表し、クローズドで本物のプライベートメンバを作成します.
    var Book = function(newIsbn,newTitle,newAuthor){
    
    
    
        //    
    
        var isbn,title,anthor;
    
        function checkIsbn(isbn){
    
        ...
    
        };
    
    
    
        //
    
        this.getIsbn = function(){
    
            return isbn;
    
        };
    
        this.setIsbn = function(){
    
            if(!checkIsbn(newIsbn)) throw new Error('Book:Invalid ISBN.');
    
            isbn = newIsbn;
    
        };
    
        this.getTitle = function(){
    
            return newTitle;
    
        };
    
        this.setTitle = function(newTitle){
    
            title = newTiyle||'';
    
        };
    
        this.getAuthor = function(){
    
            return author;
    
        };
    
        this.setAuthor = function(newAuthor){
    
            author = newAuthor||'';
    
        };
    
    
    
        this.setIsbn(newIsbn);
    
        this.setTitle(newTitle);
    
        this.setAuthor(newAuthor);
    
    }
    
    //                  prototype   。
    
    Book.prototype = {
    
        display:function(){...}
    
    }
    より高度なオブジェクトの作成.
    var Book = (function(){
    
        //      
    
        var numOfBooks = 0;
    
        //      
    
        function checkIsbn(isbn){
    
        ...
    
        };
    
    
    
        return function(newIsbn,newTitle,newAuthor){
    
            //    
    
            var isbn,title,anthor;
    
    
    
            //
    
            this.getIsbn = function(){
    
                return isbn;
    
            };
    
            this.setIsbn = function(){
    
                if(!checkIsbn(newIsbn)) throw new Error('Book:Invalid ISBN.');
    
                isbn = newIsbn;
    
            };
    
            this.getTitle = function(){
    
                return newTitle;
    
            };
    
            this.setTitle = function(newTitle){
    
                title = newTiyle||'';
    
            };
    
            this.getAuthor = function(){
    
                return author;
    
            };
    
            this.setAuthor = function(newAuthor){
    
                author = newAuthor||'';
    
            };
    
    
    
            numOfBooks++;
    
            if(numOfBooks > 50) throw new Err('Book:only 50 instances of Book can be created.');
    
            this.setIsbn(newIsbn);
    
            this.setTitle(newTitle);
    
            this.setAuthor(newAuthor);
    
        }
    
    
    
    })();
    
    //                  prototype   。
    
    Book.prototype = {
    
        display:function(){...}
    
    }
    いくつかの簡単な説明:
  • は、まず、クローズドパケットを()で作成し、直ちに実行し、別の関数を返します.
  • の次に、戻り関数はBookに割り当てられ、構成関数となる.
  • 回、Bookが呼び出した内部層関数を実装し、外部層は静的プライベートメンバを格納することができる閉塞パケットを作成するためだけに使用される.
  • 回、checkIsbnは静的な方法として設計されているので、Bookの各例はこの静的な方法を生成しない.この方法は、インスタンスではなく構造クラスに作用する.
  • 回、これらの静的方法は、クローズドに含まれるので、クローズド中の他の方法はアクセスでき、メモリには一部しか存在しない.
  • 回、これらの方法はコンストラクタに戻る以外に、特権的な方法ではないので、コンストラクタに定義されたプライベート属性にアクセスできないと宣言しています.
  • 回、プライベート方法が静的方法として設計されるべきかどうかを判断し、経験則は、インスタンスデータにアクセスするかどうかを判断し、必要でない場合は静的方法として設計する方が効率的である.