物件的自治與智慧型化

2021-06-16 08:48:13 字數 3429 閱讀 2853

我一直強調物件是自治的,這意味著它應該擁有能表達自身物件特性的資料與行為,對自己的資料與狀態負責,對於該資料而言,物件是自給自足的。物件的自治體現了oo最基本的原則,那就是「資料與行為應該封裝在一起」。擁有行為能力的物件,就好比擁有了意識,擁有了智慧型,它可以自行判斷,而無需別人通知。不錯,這事實上就是「好萊塢原則」的體現,但我更喜歡將其稱之為物件的「專家模式」。這種專家模式與現實社會何其相似,「專業的事情就交給專家去做吧!」軟體系統的物件應該各司其職,各盡其職,這樣才能產生合理的職責分配,從而形成完善的協作方式。

還是用案例來說話。在我們的專案中,需要對客戶發出的web請求進行處理,獲得我們需要的引數。引數的值放在request中,而我們事先已經根據配置檔案,獲得了引數的型別資訊。根據專案需要,我們將引數劃分為三種:

1、單一引數(******parameter);

2、元素項引數(itemparameter);

3、表引數(tableparameter);

因為引數的屬性是在配置檔案中已經配好,我定義了parametergraph物件。它能夠讀取引數的配置資訊,並根據引數的型別建立不同的引數物件。這些引數類共同繼承了乙個抽象的父類parameterbase,並實現了parameter介面,如下圖所示:

對於不同型別的引數,有著不同的處理邏輯。例如,對於tableparameter而言,它在客戶端瀏覽器的表單中,事實上表現為乙個表,然後以行、列以及資料單元格的名稱作為map的key值,而value則是乙個字串陣列。當我寫出這樣的**時,我的直覺告訴我,這樣的**是醜陋的,一定存在某些問題。那麼問題出在**呢?首先,在這個方法中,存在分支語句,它會判斷parameter物件的執行時型別,以此決定不同的處理邏輯。為什麼要這樣做,從上面的類圖可以看出,對於不同的parameter物件,值是不相同的,即擁有各自不同的方法,例如getvalue()、additem()與addelement()等。而這些方法是不同抽象到它們共同的父類或介面中,因此必須轉換為具體型別,再進行處理。

現在,讓我們從兩個角度來思考問題。首先,閱讀分支語句的執行邏輯,它所要處理的資料是屬於誰的?除了提供引數資料來源的request物件,這些資料都是屬於各自引數物件的。例如,針對tableparameter,雖然看起來是在建立tableparameterelement物件,但實質上該物件本身就屬於tableparameter的乙個組成元素。itemparameter與******parameter同樣如此。根據前面所述的「資料與行為應該封裝在一起」原則,我們似乎應該將各個分支的處理邏輯封裝到各自的parameter類中。事實上,reportparameteraction類只關心對引數的收集,並不需要知道引數收集的具體實現。因此,無論是從封裝還是職責分配的角度來看,這裡的事先都存在問題。

讓我們再站在抽象的角度思考問題。前面提到不同引數有不同的值,且這些值分別屬於不同的型別,操作方式也不相同,因而無法抽象。事實上,這裡違背了抽象的原則,就是過於關注實現細節,而沒有從共性特徵的角度去分析介面。在前面的分析中,實質上我已經隱隱約約提到了這個共同特徵:即無論設定什麼值,其本質都是將資料填充到引數中,至於如何填充,則屬於實現細節的範疇。因此,我們可以在parameter介面中定義如下方法:

public

inte***ce parameter

注意,我在filldata()方法中玩了乙個花招。我們可以比較之前的collectparameters()方法,它接收的引數為servletrequest物件,現在filldata()方法的引數變成了parameterrequest,發生了什麼事?

原因有二。其一,servletrequest類是由servlet提供的,parameter要使用它,就必須依賴於servlet包,這實在有些得不償失。其二,servletrequest介面是乙個龐大的介面,它很難被實現。設想我們如果要對parameter進行單元測試,則很難模擬servletrequest,而事實上,這裡僅僅需要呼叫servletrequest介面的getparametervalues()方法即可。正因為如此,我引入了parameterrequest介面,它僅定義了乙個getparametervalues()方法:

public

inte***ce parameterrequest

對於這樣乙個介面,我們很容易模擬它的實現,而對於呼叫者reportparameteraction而言,也很容易將servletrequest物件轉為parameterrequest的實現。好了,這裡的設計事實上體現了物件的「間接」以及單一職責原則,通過引入間接的介面來解除耦合。不過,這應該是另外乙個故事了。讓我們繼續回過頭來看引數的處理。我們將之前collectparameters()方法的實現轉移到各個parameter子類的filldata()實現中:

public

class ******parameter 

extends parameterbase  

} public

class itemparameter 

extends parameterbase  

} } 

public

class tableparameter 

extends parameterbase  

} }  }

現在,這些parameter的子類就是自治的物件,它能夠處理屬於自己的資料,而不需要外界(呼叫者)來告知它,它充分享有智慧型判斷的能力。讓我們看看修改後的客戶端**:

private mapcollectparameters(servletrequest request, parametergraph parametergraph)  

); } 

return parametergraph.getparameters();  }

現在,parameter物件能夠根據自己的型別對從request中取出來的資料進行處理。reportparameteraction的collectparameters()方法就不用操心這些煩人的處理邏輯,**結構變得更加清晰,尤其是職責的劃分更為準確。這種對引數職責有效的封裝方式,還有利於引數型別的擴充套件。倘若增加了新的引數型別,只需要定義繼承自parameterbase類的子類即可,不會影響到任何客戶呼叫**。這就是自治物件的好處。記住,當我們需要分配職責時,就應該考慮自治原則與專家模式,並設身處地站在該物件的角度去思考問題,想一想,如果你就是這個物件,應該完成哪些職責,而哪些職責又應該委派給別的物件。

原文:

智慧型化與私隱性

未來必然是智慧型的時代,你準備好張開懷抱了麼 隨著時代科技的進步,我們的生活也發生了翻天覆地的變化。科技給我們帶來了想象不到的各種便利。打車不需要跑到大馬路上招手,吃飯不需要頂著烈日出去,購物不需要去商場。現在的物聯網也是火熱的進行當中。在智慧型家居中,很體貼的幫你開關窗,把室內調整到事宜的溫度,記...

智慧型化的今天

又到了年底,又到了一年一度取醫保存摺裡錢的日子了。每年年底都要從醫保存摺裡把錢取出來,這習慣保留了有幾年了。今年自然也不例外。今天,去了趟北京銀行。醫保取款機前意料之中的排著一隊長龍。心想先辦個卡吧,省著再跑了,去年就想著辦卡,但排隊的人太多遂放棄。走到服務台,說取個號,辦銀行卡。結果大堂經理說,辦...

時尚數位化與智慧型化

ai加持時尚行業 人工智慧將真正實現時尚商品的數位化和智慧型化,重新定義人 貨 場之間的關係,進一步加進人與商品的距離,優化商品企劃 設計 生成與流轉的形式。衣食住行,民生四大領域 在服裝行業有2.8萬億的市場規模 服飾數位化 ocr 標籤資料ocr檢測識別服飾標籤資料中的文字 演算法應用 服飾屬性...