JavaScriptシリーズを深く理解する(21):S.O.L.I.D 5原則のインターフェース分離原則ISP詳細解

4546 ワード

前言
この章で説明したいのはS.O.L.I.D 5大原則JavaScript言語で実現された第4編で、インターフェース隔離原則ISP(The Interface Segregation Principle)です。
英語の原文:http://freshbrewedcode.com/derekgreer/2012/01/08/solid-javascript-the-interface-segregation-principle/ この文章は作者が回り道をしていますので、おじさんも気がふさいでいます。適当に見てください。インターフェースの隔離原則に深くはまらないように説明しています。
 
  
Clients should not be forced to depend on methods they do not use.
それらを使わない方法にお客さんに依存させるべきではない。
ユーザに依存するインターフェース方法が他のユーザだけによって使用されても自分で使用されなくても、これらのインターフェースは実現されなければならない。言い換えれば、1人のユーザは未使用に依存しているが、他のユーザによって使用されるインターフェースは、他のユーザがこのインターフェースを修正すると、そのインターフェースに依存するすべてのユーザが影響を受けるだろう。これは明らかに開閉の原則に違反しています。私たちが望むものでもありません。
インターフェース分離の原則ISPと単一の職責は似ていて、機能職責を集めるために用いられています。実際にISPは単一の職責を有するプログラムが公共インターフェースを有するオブジェクトに転化することが理解されます。
JavaScriptインターフェース
JavaScriptの下で私たちはこの原則をどうやって守るべきですか?やはりJavaScriptにはインターフェースの特性がないので、インターフェースというのは、ある言語で提供される抽象的なタイプを通してcontractと結合を確立するということです。それはいいです。でも、JavaScriptには別の形のインターフェースがあります。Design Patternsで、C Elements of Reusable Object-Oriented Softwareという本の中でインターフェースの定義を見つけました。http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612
オブジェクト宣言のいずれかの動作には、操作名、パラメータオブジェクト、および動作の戻り値が含まれます。私たちはオペレータのサインと呼びます。一つのオブジェクト内の声明のすべての操作をこのオブジェクトのインターフェースと呼びます。一つのオブジェクトのインターフェースは、このオブジェクトに発生するすべての要求情報を描写している。一つの言語が単独の構成を提供するかどうかに関わらず、インタフェースを表しています。すべてのオブジェクトには、そのオブジェクトのすべての属性と方法からなる暗黙のインターフェースがあります。参考コード:
 
  
var exampleBinder = {};
exampleBinder.modelObserver = (function() {
    /* */
    return {
        observe: function(model) {
            /* */
            return newModel;
        },
        onChange: function(callback) {
            /* */
        }
    }
})();

exampleBinder.viewAdaptor = (function() {
    /* */
    return {
        bind: function(model) {
            /* */
        }
    }
})();

exampleBinder.bind = function(model) {
    /* */
    exampleBinder.modelObserver.onChange(/* callback */);
    var om = exampleBinder.modelObserver.observe(model);
    exampleBinder.viewAdaptor.bind(om);
    return om;
};

上のexampleBinderクラスで実現される機能は双方向結合です。このクラスの暴露された共通インターフェースは、bindで使用されるchange通知とviewインタラクションの機能は、それぞれ別のオブジェクトmodelObserverとview Adaptorによって実現され、これらのオブジェクトはある意味で公共インターフェースbind方法の具体的な現実である。
JavaScriptは、オブジェクトのcontractをサポートするインターフェースタイプを提供していませんが、オブジェクトの隠しインターフェースは、プログラムユーザにcontractとして提供されています。
ISPとJava Script
私達が以下で検討しているいくつかの小節はJavaScriptの中でインターフェースの隔離の原則に違反する影響です。上に見たように、JavaScriptプログラムでインターフェース分離の原則を実現するのは残念ですが、静的なタイプの言語ほど強大ではないです。JavaScriptの言語特性は時々いわゆるインターフェースを粘着しないようにします。
堕落した実現
静的なタイプの言語の中で、ISPの原則に違反する1つの原因は堕落する実現です。JavaとC〓〓の中ですべてのインターフェースの中で定義する方法はすべて必ず実現しなければならなくて、もしあなたはその中のいくつかの方法だけを必要とするならば、その他の方法も必ず実現しなければなりません。JavaScriptでは、オブジェクトの中のいくつかのインターフェースだけが必要であれば、彼も堕落してこの問題を実現することはできません。上のインターフェースを強制的に実現する必要はありません。しかし、このような実現は依然として裏氏交代の原則に違反しています。
 
  
var rectangle = {
    area: function() {
        /* */
    },
    draw: function() {
        /* */
    }
};

var geometryApplication = {
    getLargestRectangle: function(rectangles) {
        /* */
    }
};

var drawingApplication = {
    drawRectangles: function(rectangles) {
       /* */
    }
};

rectangles代替品が新しいオブジェクトgeometryAppleicationのgetLargstrectangleを満たすために必要なのはrectanglesのaraだけです。しかし、それはLSPに違反しています。
静的結合
静的なタイプの言語におけるもう一つのISP違反の原因は静的結合であり、静的なタイプの言語においてはインタフェースは松結合設計プログラムで大きな役割を果たしている。動的言語においても、静的言語においても、あるオブジェクトは複数のクライアントユーザと通信する必要があります。静的タイプの言語に対しては、Role Interfacesを使用して、ユーザとそのオブジェクトとの間のコミュニケーションが可能です。その実装としてユーザーと無関係の挙動をデカップリングする。JavaScriptではこのような問題はありません。対象はすべて動的言語特有の長所によって結合されています。
意味結合
ISPに違反する共通の原因の一つとして、動的言語と静的タイプ言語があります。つまり意味結合とは相互依存、つまりオブジェクトの動作が他のオブジェクトに依存することであり、ユーザーがその行動を変えたら、他のユーザーの利用に影響を与える可能性が高いということです。これも単一職責原則に違反しました。この問題は継承と対象の代替によって解決できます。
拡張性
もう一つの問題の原因は拡張可能性についてです。多くの人が例を挙げてcalbackに関する例を挙げて、拡張可能性を示しています。このようなインターフェースを実現したいならば、この実現の対象に多くの熟知や方法があれば、ISPは非常に重要になります。つまりインターフェースのinterfaceが必要になって多くの方法を実現すると、彼の実現は非常に複雑になり、またこれらのインターフェースが粘性のない役割を担う可能性があります。これは私たちがよく話している太いインターフェースです。
締め括りをつける
JavaScriptにおける動的言語の特性は、静的なタイプの言語よりも非粘性インターフェースの影響力が小さいことを実現していますが、インターフェース隔離の原則はJavaScriptプログラムの設計モードにおいても依然としてその役割を果たしているところがあります。