每一個(gè)階段,我對(duì)設(shè)計(jì)模式都有不同的理解盒使。
隨著對(duì)函數(shù)式編寫(xiě)的熱愛(ài)艇劫,對(duì)關(guān)系型數(shù)據(jù)庫(kù)和文檔型數(shù)據(jù)庫(kù)的對(duì)比吼驶,我對(duì)設(shè)計(jì)模式又有了新的感覺(jué)。
我覺(jué)得范例總是最有效的說(shuō)明店煞,假設(shè)我們以一個(gè)餐館來(lái)作為對(duì)象(我的英文不怎么樣蟹演,就不要計(jì)較拼寫(xiě)了):
Eatery (餐館類(lèi))
首先,有了一個(gè)餐館類(lèi)顷蟀,然后加上餐館提供的接口酒请,餐館就可以工作了。目前鸣个,先提供:
milk() // 來(lái)份牛奶
rice() // 來(lái)份炒飯
當(dāng)然羞反,還得有餐館建立的時(shí)間、城市囤萤、老板昼窗、雇員、價(jià)格...于是還得加上下面的:
build_date // 建立日期
city // 所在城市
boss_a // 老板a
employee_a // 雇員a
employee_b // 雇員b
employee_c // 雇員c
price_milk // 牛奶價(jià)格
price_rice // 炒飯價(jià)格
menu_milk // 牛奶菜單
menu_rice // 炒飯菜單
另外涛舍,客人進(jìn)來(lái)餐館澄惊,還要報(bào)價(jià)不是,所以,還得加上:
get_price() // 報(bào)價(jià)
如果要做成程序缤削,還得報(bào)告建立的日期窘哈、城市...所以,還得加上:
get_build_date() // 報(bào)告建立日期
get_city() // 報(bào)告所在城市
get_boss() // 報(bào)告有哪幾個(gè)老板
get_employee() // 報(bào)告有哪幾個(gè)雇員
get_price() // 報(bào)告菜品價(jià)格
get_menu() // 報(bào)告菜單上的菜
先大致如此吧亭敢,于是,得到了一個(gè)可以使用的餐館了:
Eatery:
build_date // 建立日期
city // 所在城市
boss_a // 老板a
employee_a // 雇員a
employee_b // 雇員b
employee_c // 雇員c
price_milk // 牛奶價(jià)格
price_rice // 炒飯價(jià)格
menu_milk // 牛奶菜單
menu_rice // 炒飯菜單
get_build_date() // 報(bào)告建立日期
get_city() // 報(bào)告所在城市
get_boss() // 報(bào)告有哪幾個(gè)老板
get_employee() // 報(bào)告有哪幾個(gè)雇員
get_price() // 報(bào)告菜品價(jià)格
get_menu() // 報(bào)告菜單上的菜
milk() // 來(lái)份牛奶
rice() // 來(lái)份炒飯
目前图筹,餐館應(yīng)該是這么運(yùn)作的:
告訴我餐館建立日期 get_build_date()
告訴我餐館所在城市 get_city()
告訴我餐館菜單上的菜 get_menu()
告訴我餐館菜單上的價(jià)格 get_price()
給我來(lái)一個(gè)牛奶 milk()
給我來(lái)一份炒飯 rice()
現(xiàn)在帅刀,先不管面向?qū)ο螅葋?lái)想想關(guān)系型數(shù)據(jù)庫(kù)远剩,要做個(gè)餐館的數(shù)據(jù)庫(kù)該怎么打草稿?
table_eatery: 起個(gè)名字扣溺, 從餐館的基礎(chǔ)來(lái)開(kāi)始吧
id // 現(xiàn)在當(dāng)然只有一個(gè)餐館
build_date // 建立日期
city // 所在城市
是不是應(yīng)該是這樣的?
我們總是保持基礎(chǔ)的那個(gè)表格盡可能簡(jiǎn)單高效.
這份表格告訴我們 : 餐館建立日期和所在城市瓜晤,還有通過(guò)id號(hào)能獲取到這個(gè)餐館锥余。
就這么多!
如果想知道餐館的老板怎么辦痢掠?
簡(jiǎn)單驱犹!
建個(gè)表格,show me the info:
table_boss:
id
boss_name
eatery_id
應(yīng)該是這樣的足画。
通過(guò)id號(hào)取到某個(gè)老板雄驹,然后還有一個(gè)關(guān)聯(lián)的餐館號(hào)碼eatery_id.
老板肯定是某個(gè)餐館的老板,
老板boss_a當(dāng)然是eatery_id號(hào)碼這個(gè)餐館的老板淹辞。
更多的先不討論了医舆。
因?yàn)椋@里象缀,
有意思的地方已經(jīng)出來(lái)了蔬将。
table_eatery和table_boss全面的揭示了面向?qū)ο蟮谋举|(zhì):
擴(kuò)展和關(guān)聯(lián)
我們先建立起基礎(chǔ):eatery,然后呢央星?
當(dāng)我們需要新的東西的時(shí)候霞怀,擴(kuò)展eatery。
怎么擴(kuò)展呢等曼?
通過(guò)建立一個(gè)新的表格里烦。
那新的表格table_boss怎么跟table_eatery建立聯(lián)系呢?
通過(guò)在新擴(kuò)展出來(lái)的table_boss塞入eatery_id來(lái)指向table_eatery禁谦。
乍一看胁黑,是不是就是繼承呢?
先弄出個(gè)table_eatery對(duì)象州泊,然后繼承這個(gè)對(duì)象丧蘸,在上邊再弄上個(gè)boss_name。
不過(guò),仔細(xì)觀察 力喷,當(dāng)然知道不是繼承刽漂。 (而且,都知道弟孟,多數(shù)時(shí)候繼承不是好的面向?qū)ο螅?/p>
這里是"組合"贝咙。
在新的對(duì)象里放入舊有對(duì)象的一個(gè)引用,然后拂募,成了庭猩。
objectA ---> objectB [放入objectA的一個(gè)引用]
以此類(lèi)推,我們加深下關(guān)系型數(shù)據(jù)庫(kù)表格的建立陈症。
建立一個(gè)雇員表格:
id
employee_name
eatery_id
建立一個(gè)餐館菜單:
id
menu_item
menu_price
eatery_id
...
這其實(shí)就是面向?qū)ο蟮倪^(guò)程蔼水。
所以,對(duì)于程序來(lái)說(shuō)录肯,設(shè)計(jì)這個(gè)餐館趴腋,可以這樣面向?qū)ο?
Eatery (build_date, city)
build_date // 建立日期
city // 所在城市
get_build_date() // 報(bào)告建立日期
get_city // 報(bào)告所在城市
Boss (eatery)
name // 老板名字
set_name // 任職老板
get_name // 當(dāng)前老板的名字
Employee (eatery)
names // 雇員們的名字
add_name // 增加一個(gè)雇員
remove_name // 開(kāi)除一個(gè)雇員
get_name(i) // 報(bào)告第幾號(hào)雇員的名字
get_names() // 報(bào)告所有的雇員名字列表
Food (name, price)
name // 菜的名字
price // 菜的價(jià)格
get_name() // 報(bào)告菜的名字
get_price() // 報(bào)告菜的價(jià)格
Menu (eatery)
foods // 菜列表
add_food(food) // 加入菜
remove_food(food) // 刪除菜
get_food_price(i) // 報(bào)告第幾號(hào)菜的價(jià)格
get_food_prices // 報(bào)告所有菜的價(jià)格
get_food_names // 報(bào)告所有菜的名字
get_food_name(i) // 報(bào)告第幾號(hào)菜的名字
Cook (name, food_names)
name // 廚師名字
food_names // 廚師擅長(zhǎng)做的菜名
get_name() // 報(bào)告廚師的名字
get_food_names() // 報(bào)告廚師擅長(zhǎng)做的菜名列表
make(food_name) // 廚師制作名為food_name的菜
Cooklist (eatery)
cooks // 餐館entery雇傭的廚師名字列表
add_cook(cook) // 增加一個(gè)廚師
get_cook_names() // 報(bào)告所有的餐館廚師名字
get_cook_name(i) // 報(bào)告第幾號(hào)廚師的名字
OK. 餐館構(gòu)造完畢,現(xiàn)在论咏,開(kāi)始運(yùn)營(yíng):
var entery_pie = new Eatery('2014-5-1', 'Beijing'); // 2014年5月1日优炬,在北京建立餐館pie
entery_pie.get_build_date(); // => 2014-5-1
entery_pie.get_city(); // => Beijing
var boss = new Boss(eatery_pie); // 為餐館pie指認(rèn)老板
boss.set_name('Tom'); // 老板是Tom
var employee = new Employee(eatery_pie); // 為餐館pie雇傭員工
employee.add_name('Lili'); // 雇傭Lili
employee.add_name('Lina'); // 雇傭Lina
employee.add_name('Jerry'); // 雇傭Jerry
employee.get_names(); // => Lili,Lina,Jerry
employee.get_name(1); // => Lina
var menu = new Menu(eatery_pie); // 為餐館pie開(kāi)設(shè)菜單
menu.add_food(new Food('milk', '12.00¥')); // 加入價(jià)格12.00¥的牛奶
menu.add_food(new Food('rice', '26.00¥')); // 加入價(jià)格26.00¥的炒飯
menu.get_food_names(); // => 牛奶,炒飯
menu.get_food_prices(); // => 12.00¥,26.00¥
menu.get_food_name(1); // => 炒飯
var cooklist = new Cooklist(eatery_pie); // 為餐館pie增加廚師
cooklist.add_cook(new Cook('Daxiong', ['milk', 'rice', 'tomoto'])); // 增加一個(gè)會(huì)做牛奶、炒飯潘靖、西紅柿的廚師
cooklist.add_cook(new Cook('Xiaoxiao', ['milk', 'rice'])); // 增加一個(gè)會(huì)做牛奶穿剖、炒飯的廚師
cooklist.get_cook_name(1).make('milk'); // Xiaoxiao廚師來(lái)一份牛奶
cooklist.get_cook_name(0).make('tomoto'); // Daxiong廚師來(lái)一份西紅柿
這就是我現(xiàn)在思想中的面向?qū)ο螅赡芎?jiǎn)單的模型卦溢,更多的擴(kuò)展和關(guān)聯(lián)糊余。
在很長(zhǎng)時(shí)間之前,我收集到的信息告訴我单寂,盡可能的封裝贬芥,并且 a.get().method() 表現(xiàn)的不夠隱蔽。
如果有a.get().nethod()宣决,應(yīng)該盡可能換成a.method()來(lái)隱藏蘸劈。
然而,現(xiàn)在我卻感覺(jué)到這樣教條式的做法尊沸,在許多時(shí)候是多余和低效的威沫。
比起把許多小對(duì)象裝起來(lái),扔到一個(gè)大對(duì)象里封裝洼专,我現(xiàn)在更喜歡建立一大堆的小對(duì)象棒掠,然后分批指派責(zé)任。
從許多方面來(lái)看屁商,簡(jiǎn)化代碼行數(shù)的外觀模式都是反模塊化的烟很,只用一個(gè)對(duì)象來(lái)操縱一大堆函數(shù)。
事實(shí)上,底層要通過(guò)層層傳遞雾袱,才能夠到達(dá)真正實(shí)現(xiàn)功能的地方恤筛。
這既是低效的,在編寫(xiě)擴(kuò)展的時(shí)候而且很困難芹橡。
如果你寫(xiě)完一個(gè)夠大的對(duì)象毒坛,當(dāng)需要增加內(nèi)容的時(shí)候,就會(huì)對(duì)這個(gè)對(duì)象的關(guān)聯(lián)“鏈”一籌莫展林说。
而打散的小對(duì)象群粘驰,更貼近函數(shù)式的風(fēng)格,只需要指定源對(duì)象的引用述么,就可以擴(kuò)展ta,而且是采用組合而不是繼承愕掏。
而且度秘,在某些方面,你會(huì)發(fā)現(xiàn)這其實(shí)就是函數(shù)式.
一個(gè)數(shù)據(jù)結(jié)構(gòu)Eatery饵撑,以及一大堆圍繞數(shù)據(jù)結(jié)構(gòu)Eatery的函數(shù)群:
eatery
fn1(eatery, arg1, arg2, ...)
fn2(eatery, arg1, arg2, ...)
fn3(eatery, arg1, arg2, ...)
...
好處是剑梳,非常易于擴(kuò)展(增加功能,增加內(nèi)容滑潘,增加關(guān)聯(lián)垢乙,...)和修改.
壞處是? e, ... 语卤,相比較傳統(tǒng)的OO教學(xué)追逮,會(huì)有一大堆“小星星”散亂在宇宙世界里,變得不那么透明粹舵,但是依然可以設(shè)定一個(gè)邊界來(lái)限定這個(gè)外層钮孵。
但是,我覺(jué)得眼滤,好處是絕對(duì)的巴席,因?yàn)檫@樣更符合函數(shù)的特性:
輸入一個(gè)值,show me the result
fn1(eatery_pie, arg1, arg2) => 餐館pie的信息