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

作者: Tulayang | 来源:发表于2014-09-12 16:36 被阅读355次

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

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

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

    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的信息 
    

    相关文章

      网友评论

        本文标题:简单而有效的深入设计模式

        本文链接:https://www.haomeiwen.com/subject/dnaytttx.html