摘要:按信息熵的觀點(diǎn)這種模式對熵的降低最大。但是,這將增加處理程序的復(fù)雜性,程序并不能輕松的自動處理,或者要將多對多關(guān)聯(lián)分解成純粹的和有其他數(shù)據(jù)的兩種模式。模式是普遍存在的,從到。
4月份遺漏了一篇,這篇算是補(bǔ)充。
此文并非對設(shè)計(jì)模式的總結(jié),而是要談?wù)勔话愕木幋a風(fēng)格,找設(shè)計(jì)模式的朋友可以移步了。
什么是模式?我搜到一個簡短的解釋:模式是指從生產(chǎn)經(jīng)驗(yàn)和生活經(jīng)驗(yàn)中經(jīng)過抽象和升華提煉出來的核心知識體系。
模式是多個生活、生產(chǎn)行為的歸納總結(jié),也就是解決某一類問題的方法論。從信息的角度來理解,模式是對信息減小信息熵的過程和結(jié)果。
比如一個 APP 需要組織一個表單,表單里的部分元素如選項(xiàng)列表由服務(wù)器提供,假設(shè)是一個行業(yè)列表,通??赡芏x一個列表:
[ {trade_id: 10, trade_name: "xdfsdf"}, ... ]
看上去接口提供的這個數(shù)據(jù)沒什么問題。如果此時表單里還有選項(xiàng)列表,選擇城市,那你可能很自然想到 {city_id: 25, city_name: "wefel"} 。對于客戶端,問題也不大,MVC 模式嘛,我在 Model 里分別指定不就行了。
嗯,你也許猜到我想說什么了,沒錯,我想用一個可更簡單的、可復(fù)用的結(jié)構(gòu)來進(jìn)行描述。如:
[ {id: 10, name: "xdfsdf"}, ... ]
甚至:
[ [10, "xdfsdf"], ... ]
這樣對此類控件可以更容易的封裝使用。按信息熵的觀點(diǎn)這種模式對熵的降低最大。
但這種轉(zhuǎn)換您可能嗤之以鼻:『切,這算什么模式?』
我覺得當(dāng)開始思考模式時,就是在思考事物與事物間的關(guān)聯(lián),這才是一個程序員(Programmer)該做的事情;如果僅僅是為了寫點(diǎn)代碼實(shí)現(xiàn)某個功能,那該叫編碼員(Coder)。
對照模式的解釋,算法也是模式;我念書少,一直對算法掌握的比較弱,所以此文也就不班門弄斧了。在這里對僅對常規(guī)的 MIS(管理信息系統(tǒng))的接口數(shù)據(jù)結(jié)構(gòu)提出一些看法,主要針對數(shù)據(jù)的 CRUD(增刪改查)。
假設(shè)要為一家餐館做一個小型 App,需求是構(gòu)建菜譜,有單品,有套餐。單品的屬性有:名稱、單價、簡介、照片(多個,文件、說明),套餐有:名稱、折扣價、簡介、餐品(多個)。繪制 ERM 如下:
單品和套餐通??梢猿霈F(xiàn)在一個搜索列表里,屬性基本一致,故放在同一張表里(模式出現(xiàn)了)。照片能夠復(fù)用,比如單品可以引用,某個套餐也可以用,甚至系統(tǒng)其他的地方也可以用(這就是模式),那就獨(dú)立出來好了(沒有 Product_id 而是用 Product_has_Picture 的多對多關(guān)系)。
下面我們開始設(shè)計(jì) REST 接口:
GET /xxx/products Response Content: [ { id: "商品 ID", name: "名稱", note: "簡介", price: "價格, 格式: RMB ###.##", is_package: "是否是套餐", main_picture: "主要展示照片 URL" } ] GET /xxx/products/ID Response Content: { id: "Product ID", name: "名稱", note: "簡介", price: "價格, 格式: RMB ###.##", is_package: "是否是套餐", pictures: [ { id: "照片 ID", name: "名稱", note: "簡介" } ], products: [ { id: "商品 ID", name: "名稱", note: "簡介", price: "價格, 格式: RMB ###.##", main_picture: "主要展示照片 URL", is_free: "是否免費(fèi)附送" } ] } POST /www/products PUT /www/products/ID Request Content: { name: "名稱", note: "簡介", price: "價格, 格式: RMB ###.##", is_package: "是否是套餐", pictures: [ { Picture_id: "照片 ID", is_main: "0或1" } ] } DELETE /www/products/ID
看上去沒什么特殊的呀!細(xì)心的話也許發(fā)現(xiàn)了,GET 拿到的 pictures 列表與 POST、PUT 發(fā)送的 pictures 列表結(jié)構(gòu)不一致,這是根據(jù)我的框架能識別的模式所做的精簡,事實(shí)上 pictures 的完整結(jié)構(gòu)為:
Product_has_Picture: [ { Product_id: "商品ID", Picture_id: "照片ID", is_main: "是否是主照片", Picture: { id: "照片ID", name: "照片名稱", note: "照片說明" } } ]
在進(jìn)行商品的創(chuàng)建和修改時,由于照片是從照片列表(接口)選擇的,故 Picture 層是不需要的。如果用類似 Protobuf 的方式描述 Product 的數(shù)據(jù)結(jié)構(gòu),應(yīng)該是:
message Picture { required int323 id = 1; required string name = 2; required string note = 3; } message Product { required int32 id = 1; required string name = 2; optional string note = 3; required float price = 4; optional bool is_package = 5; message Pictures { required Picture picture = 1; optional bool is_main = 2 [default = 0]; } repeated Pictures pictures = 6; message Products { required Product product = 1; optional bool is_main = 2 [default = 0]; } repeated Products products = 7; }
可以看出 Pictures 內(nèi)是單個的 Picture 對象,重復(fù)的是 Pictures 對象;如果僅僅按數(shù)據(jù)結(jié)構(gòu)越簡單越好的模式來評判,假設(shè) Pictures 列表不需要 is_main 屬性,按第一個圖即為默認(rèn)圖的方式好了,也就是 Product 內(nèi)直接定義 repeated Picture pictures。那么,PUT Product 時 pictures 可定義為一個由 ID 組成的列表甚至分隔符分隔的字符串。但是,這將增加處理程序的復(fù)雜性,程序并不能輕松的自動處理,或者要將多對多關(guān)聯(lián)分解成純粹的和有其他數(shù)據(jù)的兩種模式。
這里涉及到另一個模式,我們的數(shù)據(jù)關(guān)聯(lián)方式到底有多少種,多數(shù)的 ORM 框架會給你這樣幾種:BLONGS_TO HAS_ONE HAS_MANY MANY_TO_MANY,但當(dāng)從 ERM 轉(zhuǎn)為類圖的時候,你會發(fā)現(xiàn)其實(shí)只有一種關(guān)系即可完整覆蓋這 4 種關(guān)系,那就是 BELONGS_TO,在類圖里叫 Dependency (個人覺得對 UML 的 Association Aggregation 等其他名詞沒必要太較勁)。
為了顯式的申明當(dāng)前關(guān)聯(lián)查詢的表,確定關(guān)聯(lián)方向,保留 HAS_ONE、HAS_MANY 便于理解(其實(shí)是我嫌麻煩,Django 就做到了只要申明了 ForeignKey 就可以正、反雙向的關(guān)聯(lián)查詢),由此可得出 A MANY_TO_MANY C 可以分解為 A HAS_MANY B (by A_ID) BELONGS_TO C (by C_ID)。
當(dāng)理清楚了這個結(jié)構(gòu)模式時,就可以編寫程序『自動』處理請求了,比如你給了 products 數(shù)據(jù) {product_id: 31, is_main: 1},就會去寫入 Product_has_Picture 的關(guān)聯(lián)數(shù)據(jù), 外鍵 package_id 可以自動代入。查詢商品列表時給了 products.product_id 就會提取含有某個(些)商品的套餐。
以此看來,數(shù)據(jù)本身就成了『查詢語句』和『業(yè)務(wù)邏輯』。
說完了結(jié)構(gòu)再說說行為。對于常規(guī)的 CRUD,我認(rèn)為從視覺操作上可以分解為兩個組件:列表、表單;列表對應(yīng)的接口有:獲取列表、更新;表單對應(yīng)的接口有:獲取信息、保存(增加、修改)。
獲取列表接口可涵蓋:分頁、排序、搜索(篩選)等;
列表的更新有:刪除、更新狀態(tài)(批量更新某個字段的值);
在多年以前 WEB 開發(fā)中頁面與頁面(組件)間的聯(lián)動是靠顯式的告知回跳地址或用 Referer 來回到來源處,比如連貫的行為:打開列表->添加商品->添加完成->跳回列表。
而獨(dú)立的組件模式,組件與組件之間的聯(lián)動是采用事件來驅(qū)動,A組件完成后廣播自己完成的事件,哪個組件需要處理哪個組件監(jiān)聽該事件就好了,簡單總結(jié)為:誰打開、誰負(fù)責(zé)。比如現(xiàn)有連貫操作:打開 A 列表->添加 A->進(jìn)入 A 表單->選擇 B->打開 B 列表->搜索 B->結(jié)果里沒有->添加 B->打開 B 表單->保存 B->返回 A 表單->自動選中剛添加的 B->保存 A->刷新 A 列表。
這看上去好像很麻煩,用獨(dú)立組件的方式就很好理解了:
A 列表打開 B 選擇列表,此時監(jiān)聽 B 的選擇完成事件
B 選擇列表打開 B 表單,此時監(jiān)聽 B 的保存完成事件
當(dāng) B 列表監(jiān)聽到打開的 B 表單保存完成時,觸發(fā) B 選擇完成事件
當(dāng) A 列表監(jiān)聽到打開的 B 列表選擇完成時,將選中數(shù)據(jù)加入選項(xiàng)并選中
這種方式在 App 和 Web 的 Rich Client 開發(fā)中其實(shí)很常見。此處表單的選擇是一個封裝了打開、監(jiān)聽、選中這些行為的控件;每個組件、控件都僅僅關(guān)心自己打開的組件即可,并不需要關(guān)注完整的行為;其實(shí)平時工作中的人何嘗不是如此,問題在于我們總是把問題搞得很復(fù)雜,而覺得花時間去思考它們的共性是在浪費(fèi)時間。
創(chuàng)建一個訂單,挑選幾個商品。
我要的商品不存在,那就建一個好了。純舉例,哪有餐館沒菜顧客自己動手的道理
利用模式,可以把一系列動作、判斷用一個靜態(tài)的描述來定義,比如一組表單驗(yàn)證,一個表關(guān)聯(lián)關(guān)系描述。
而在行為模式上,將關(guān)注點(diǎn)從一系列動作縮小到兩者之間關(guān)系的描述上。對程序復(fù)用和方便人操作識別都有價值。
模式是普遍存在的,從 HTTP 到 SQL。不是我們?nèi)鄙倌J?,而是太多的精力和時間耗費(fèi)在了模式的轉(zhuǎn)換上,而忽略了模式與模式間轉(zhuǎn)換的模式的思考。
模式就是要建立起一個足夠『傻』的描述,如同《阿甘正傳》里甘去見珍妮時坐在長凳上對路人說:
參考資料Mama always said "There"s an awful lot you can tell about a person by their shoes." Where they"re going. Where they"ve been.(媽媽常說看一個人的鞋子你就可以知道他的很多事情。他們要去哪里,去過哪里。)
模式 http://www.baike.com/wiki/%E6%A8%A1%E5%BC%8F
信息熵 http://baike.baidu.com/view/401605.htm
《Google Protocol Buffers 入門》 http://shitouer.cn/2013/04/google-protocol-buffers-tutorial/
《UML類圖符號 各種關(guān)系說明以及舉例》 http://www.cnblogs.com/duanxz/archive/2012/06/13/2547801.html
HongsCORE for Javascript https://github.com/ihongs/HongsCORE/tree/develop/hongs-web/web/common
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/30259.html
摘要:按信息熵的觀點(diǎn)這種模式對熵的降低最大。但是,這將增加處理程序的復(fù)雜性,程序并不能輕松的自動處理,或者要將多對多關(guān)聯(lián)分解成純粹的和有其他數(shù)據(jù)的兩種模式。模式是普遍存在的,從到。 4月份遺漏了一篇,這篇算是補(bǔ)充。 此文并非對設(shè)計(jì)模式的總結(jié),而是要談?wù)勔话愕木幋a風(fēng)格,找設(shè)計(jì)模式的朋友可以移步了。 什么是模式?我搜到一個簡短的解釋:模式是指從生產(chǎn)經(jīng)驗(yàn)和生活經(jīng)驗(yàn)中經(jīng)過抽象和升華提煉出來的核...
摘要:可水平擴(kuò)展,可以添加更多服務(wù)器來擴(kuò)展您的數(shù)據(jù)庫需要管理員是否開發(fā)人員和管理員都可以使用適用場景會計(jì)師事務(wù)所和銀行,以及需要具有清晰架構(gòu)的結(jié)構(gòu)化數(shù)據(jù)的其他公司。 今天的主題是從MongoDB漫談數(shù)據(jù)庫,在日常的項(xiàng)目中,我們一般都是使用的mysql作為數(shù)據(jù)庫,但是一旦有問題,又常常會聽到類似要不換成MongoDB試試的聲音,因此就讓我們這些小白來隨便聊聊數(shù)據(jù)庫 什么是數(shù)據(jù)庫 我們就用最簡單...
摘要:在開發(fā)設(shè)計(jì)中有一些常用原則或者潛規(guī)則,根據(jù)筆者的經(jīng)驗(yàn),這里稍微總結(jié)一下最最常用的,以饗讀者。是處理復(fù)雜性的一個原則。參考六大設(shè)計(jì)原則里氏替換原則奧卡姆剃刀如有問題可以通過郵件微信聯(lián)系我。 在開發(fā)設(shè)計(jì)中有一些常用原則或者潛規(guī)則,根據(jù)筆者的經(jīng)驗(yàn),這里稍微總結(jié)一下最最常用的,以饗讀者。 DRY 這里的DRY是Do Not Repeat Yourself的縮寫。具體解釋參見 ,嚴(yán)謹(jǐn)?shù)亩x是 E...
閱讀 3512·2021-11-15 11:38
閱讀 825·2021-11-08 13:27
閱讀 2235·2021-07-29 14:50
閱讀 2970·2019-08-29 13:06
閱讀 838·2019-08-29 11:22
閱讀 2408·2019-08-29 11:04
閱讀 3499·2019-08-28 18:23
閱讀 890·2019-08-26 13:46