简单而有效的深入设计模式

每一个阶段,我对设计模式都有不同的理解。

随着对函数式编写的热爱,对关系型数据库和文档型数据库的对比,我对设计模式又有了新的感觉。

我觉得范例总是最有效的说明,假设我们以一个餐馆来作为对象(我的英文不怎么样,就不要计较拼写了):

Eatery (餐馆类)

首先,有了一个餐馆类,然后加上餐馆提供的接口,餐馆就可以工作了。目前,先提供:

    milk()                    // 来份牛奶
    rice()                    // 来份炒饭

当然,还得有餐馆建立的时间、城市、老板、雇员、价格...于是还得加上下面的:

    build_date             // 建立日期
    city                      // 所在城市
    boss_a                  // 老板a
    employee_a           // 雇员a
    employee_b           // 雇员b
    employee_c           // 雇员c
    price_milk              // 牛奶价格
    price_rice              // 炒饭价格
    menu_milk             // 牛奶菜单
    menu_rice             // 炒饭菜单

另外,客人进来餐馆,还要报价不是,所以,还得加上:

    get_price()            // 报价    

如果要做成程序,还得报告建立的日期、城市...所以,还得加上:

    get_build_date()        // 报告建立日期
    get_city()                 // 报告所在城市
    get_boss()                // 报告有哪几个老板
    get_employee()          // 报告有哪几个雇员
    get_price()                // 报告菜品价格
    get_menu()               // 报告菜单上的菜

先大致如此吧,于是,得到了一个可以使用的餐馆了:

Eatery:

    build_date               // 建立日期
    city                        // 所在城市
    boss_a                   // 老板a
    employee_a             // 雇员a
    employee_b             // 雇员b
    employee_c             // 雇员c
    price_milk                // 牛奶价格
    price_rice                // 炒饭价格
    menu_milk               // 牛奶菜单
    menu_rice               // 炒饭菜单

    get_build_date()       // 报告建立日期
    get_city()                // 报告所在城市
    get_boss()               // 报告有哪几个老板
    get_employee()         // 报告有哪几个雇员
    get_price()               // 报告菜品价格
    get_menu()              // 报告菜单上的菜

    milk()                      // 来份牛奶
    rice()                      // 来份炒饭

目前,餐馆应该是这么运作的:

告诉我餐馆建立日期 get_build_date()

告诉我餐馆所在城市 get_city()

告诉我餐馆菜单上的菜 get_menu()

告诉我餐馆菜单上的价格 get_price()

给我来一个牛奶 milk()

给我来一份炒饭 rice()

现在,先不管面向对象,先来想想关系型数据库,要做个餐馆的数据库该怎么打草稿?

table_eatery:   起个名字, 从餐馆的基础来开始吧

    id                           // 现在当然只有一个餐馆
    build_date                // 建立日期
    city                        // 所在城市

是不是应该是这样的?

我们总是保持基础的那个表格尽可能简单高效.

这份表格告诉我们 : 餐馆建立日期和所在城市,还有通过id号能获取到这个餐馆。

就这么多!

如果想知道餐馆的老板怎么办?

简单!

建个表格,show me the info:

table_boss:

    id
    boss_name
    eatery_id

应该是这样的。

通过id号取到某个老板,然后还有一个关联的餐馆号码eatery_id.

老板肯定是某个餐馆的老板,

老板boss_a当然是eatery_id号码这个餐馆的老板。

更多的先不讨论了。

因为,这里,

有意思的地方已经出来了。

table_eatery和table_boss全面的揭示了面向对象的本质:

扩展和关联

我们先建立起基础:eatery,然后呢?

当我们需要新的东西的时候,扩展eatery。

怎么扩展呢?

通过建立一个新的表格。

那新的表格table_boss怎么跟table_eatery建立联系呢?

通过在新扩展出来的table_boss塞入eatery_id来指向table_eatery。

乍一看,是不是就是继承呢?

先弄出个table_eatery对象,然后继承这个对象,在上边再弄上个boss_name。

不过,仔细观察 ,当然知道不是继承。 (而且,都知道,多数时候继承不是好的面向对象)

这里是"组合"。

在新的对象里放入旧有对象的一个引用,然后,成了。

objectA   --->    objectB   [放入objectA的一个引用]

以此类推,我们加深下关系型数据库表格的建立。

建立一个雇员表格:

    id
    employee_name
    eatery_id

建立一个餐馆菜单:

    id
    menu_item
    menu_price
    eatery_id

...

这其实就是面向对象的过程。

所以,对于程序来说,设计这个餐馆,可以这样面向对象:

Eatery (build_date, city)

    build_date             // 建立日期
    city                      // 所在城市
    get_build_date()     // 报告建立日期
    get_city                // 报告所在城市

Boss (eatery)

    name                    // 老板名字
    set_name              // 任职老板
    get_name              // 当前老板的名字

Employee (eatery)

    names                   // 雇员们的名字
    add_name              // 增加一个雇员
    remove_name         // 开除一个雇员
    get_name(i)           // 报告第几号雇员的名字
    get_names()          // 报告所有的雇员名字列表

Food (name, price)

    name                    // 菜的名字
    price                    // 菜的价格      
    get_name()           // 报告菜的名字
    get_price()           // 报告菜的价格

Menu (eatery)

    foods                   // 菜列表
    add_food(food)      // 加入菜
    remove_food(food) // 删除菜
    get_food_price(i)   // 报告第几号菜的价格
    get_food_prices     // 报告所有菜的价格
    get_food_names    // 报告所有菜的名字
    get_food_name(i)  // 报告第几号菜的名字

Cook (name, food_names)

    name                    // 厨师名字
    food_names           // 厨师擅长做的菜名
    get_name()           // 报告厨师的名字
    get_food_names()  // 报告厨师擅长做的菜名列表
    make(food_name)   // 厨师制作名为food_name的菜

Cooklist (eatery)

    cooks                  // 餐馆entery雇佣的厨师名字列表
    add_cook(cook)     // 增加一个厨师
    get_cook_names()  // 报告所有的餐馆厨师名字
    get_cook_name(i)   // 报告第几号厨师的名字

OK. 餐馆构造完毕,现在,开始运营:

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指认老板

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开设菜单

menu.add_food(new Food('milk', '12.00¥'));  // 加入价格12.00¥的牛奶

menu.add_food(new Food('rice', '26.00¥'));  // 加入价格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'])); // 增加一个会做牛奶、炒饭、西红柿的厨师

cooklist.add_cook(new Cook('Xiaoxiao', ['milk', 'rice']));  // 增加一个会做牛奶、炒饭的厨师

cooklist.get_cook_name(1).make('milk');  // Xiaoxiao厨师来一份牛奶

cooklist.get_cook_name(0).make('tomoto');  // Daxiong厨师来一份西红柿

这就是我现在思想中的面向对象,更可能简单的模型,更多的扩展和关联。

在很长时间之前,我收集到的信息告诉我,尽可能的封装,并且 a.get().method() 表现的不够隐蔽。

如果有a.get().nethod(),应该尽可能换成a.method()来隐藏。

然而,现在我却感觉到这样教条式的做法,在许多时候是多余和低效的。

比起把许多小对象装起来,扔到一个大对象里封装,我现在更喜欢建立一大堆的小对象,然后分批指派责任。

从许多方面来看,简化代码行数的外观模式都是反模块化的,只用一个对象来操纵一大堆函数。

事实上,底层要通过层层传递,才能够到达真正实现功能的地方。

这既是低效的,在编写扩展的时候而且很困难。

如果你写完一个够大的对象,当需要增加内容的时候,就会对这个对象的关联“链”一筹莫展。

而打散的小对象群,更贴近函数式的风格,只需要指定源对象的引用,就可以扩展ta,而且是采用组合而不是继承。


而且,在某些方面,你会发现这其实就是函数式.

一个数据结构Eatery,以及一大堆围绕数据结构Eatery的函数群:

eatery

fn1(eatery, arg1, arg2, ...)

fn2(eatery, arg1, arg2, ...)

fn3(eatery, arg1, arg2, ...)

...

好处是,非常易于扩展(增加功能,增加内容,增加关联,...)和修改.

坏处是? e, ... ,相比较传统的OO教学,会有一大堆“小星星”散乱在宇宙世界里,变得不那么透明,但是依然可以设定一个边界来限定这个外层。

但是,我觉得,好处是绝对的,因为这样更符合函数的特性:

    输入一个值,show me the result

    fn1(eatery_pie, arg1, arg2) => 餐馆pie的信息 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容