每一个阶段,我对设计模式都有不同的理解。
随着对函数式编写的热爱,对关系型数据库和文档型数据库的对比,我对设计模式又有了新的感觉。
我觉得范例总是最有效的说明,假设我们以一个餐馆来作为对象(我的英文不怎么样,就不要计较拼写了):
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的信息
网友评论