看完了《JavaScript王者歸來》,在圖書館找了《JavaScript設計模式》來看,之前設計模式方面的書看過:《Head First 設計模式》、《設計模式之禪》,GOF的《Design Patterns: Elements of Reusable Object-Oriented Software》看了一部分。記得以前沒這些基礎的時候,看《JavaScript設計模式》簡直是不知道作者在說什麼。
言歸正傳:
準確的說,JavaScript沒有類的概念,都是對象,JavaScript是基於物件導向的語言,但是《JavaScript設計模式》的作者們非要說JavaScript是物件導向的(也不知道是不是翻譯的過程中問題)。用JavaScript來描述那些設計模式的時候,需要通過JavaScript的一些特性(比如說閉包、原型)來類比Java、C++等物件導向語言的一些特性(比如說類、介面、繼承、public、private)。
書中說了三種類比Interface的方法
第一種:用注釋描述介面
我覺得這個就是一種內部約定,直接說“我實現了XX介面”,在語言上我個人覺得一點約束力都沒有,這真不應該拿出來說,有點濫竽充數的感覺。
第二種:用屬性檢查模仿介面
需要一個叫做implements()的函數進行檢查
function implements(object){for(var i=1;i<arguments.length;i++){var interfaceName = arguments[i];var interfaceFound = false;for(var j=0;j<object.implementsInterfaces.length;i++){if(object.implementsInterfaces[j] == interfaceName){ //implementsInterfaces儲存了介面定義的方法的名稱interfaceFound = true;break;}}if(!interfaceFound){return false; //介面沒有找到}}return true; }
這是《JavaScript設計模式》書中的一部分代碼,作者的描述是這樣的:
這種方法有幾個優點。它對類所實現的介面提供了文檔說明。如果需要的介面不在一個類宣稱支援的介面之列,你會看到錯誤訊息。通過利用這些錯誤,你可以強迫其他程式員聲明這些介面。這種方法的主要缺點在於它並未確保類真正實現了自稱實現的介面。只知道它是否說自己實現了介面,在建立一個類聲明它實現了一個介面,但後來在實現該介面方法所規定的方法時卻漏掉其中的某一個,找一個錯誤很常見,此時所有的檢查都能通過,但那個方法卻並不存在,這將在代碼中埋下一個隱患。
隨即引出了第三中方法:用鴨式辨型模仿介面
原理:如果對象具有與介面定義的方法同名的所有方法,那麼就可以認為它實現了這個介面。
首先需要一個介面類Interface
var Interface = function(name ,methods){…… }
接受兩個參數:介面名稱,方法名
這個Interface類還有一個靜態方法 ensureImplements()
Interface.ensureImplements = function(object){……}
實際用法是這樣的:
var Composite = new Interface('Composite',['add','remover','getChild']); var FormItem = new Interface('FormItem',['save']); var CompositeForm = function(id,method,action){…… } function addForm(formInstance){ensureensureImplements(formIntance,Composite,FormItem);//This function will throw an error if a required method is not implemented…… }
最後作者採用第一種和第三種方法實現介面,代碼如下:
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(type methods[i] !=='string'){throw new Error("Interface constructor expects method names to be passed in as a string");}this.methods.push(methods[i]);} }; Interface.ensureImplements = function(object){if(arguments.length<2){throw new Error("Function Interface.ensureImplements call 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 instance 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 implements the"+interface.name+"interface.Method"+method+"was not found");}}};
JavaScript在我之前乃至現在的印象中,他就是應用在瀏覽器用戶端的的一個指令碼語言,主要的應用對象是瀏覽器,他需要這麼大費周章的去類比類似java的特性嗎?有這個需求嗎?我現在還沒發現,以後可能能發現。
設計模式在我的理解就是四個字:解耦、複用。
可能是我現在需求還沒那麼高,,沒辦法理解設計模式在JavaScript裡作用