冒号和他的学生们(连载12)——情景范式 - 编程入门网
,返回该顾客
private Customer accept() {…}
// 为指定顾客提供所有的餐馆服务
private void serve(Customer customer) {…}
// 餐馆服务
public void service()
{
while (true) // 无限循环,假设餐馆7×24小时营业
{
final Customer customer;
if ((customer = accept() ) != null) // 某顾客来访
{
serve(customer); // 为该顾客提供服务
}
}
}
}
冒号和他的学生们(连载12)——情景范式(3)时间:2011-07-01 BlogJava 郑晖冒号解说道:“这里accept类似Socket的accept,属于堵塞呼叫(blocking call),意味着此方法将堵塞进程直至收到新数据。为简单计,把一行顾客当作一个Customer。大家对此段代码有何看法?” “没什么,很简单啊。”逗号说完补充一句,“关键是serve方法的实现。” “这里我们明显用到了两个范式,对象式和过程式。”冒号提示道。 引号会意:“应该还需要并发式。serve如果与service在同一线程中运行,那么餐馆只有等服务完一个Customer后才能服务后面的,这显然是荒唐的。” “对极了!”冒号将“serve(customer);”改写为—— // serve(customer); // 错误地使用单线程! new Thread // 构造一个线程 (new Runnable() { public void run(){ Restaurant.this.serve(customer); } }).start(); // 启动该线程 冒号解释:“这回serve在新线程中运行,不会耽误Restaurant服务下一位Customer了。” 问号眼尖:“我注意到声明customer时前面加上了关键字final,有必要吗?” “如果不用线程,是不必要的。”冒号回应道,“我们在建造线程时用到了实现Runnable接口的匿名类(anonymous class),它是涉及到局部变量customer的内部类(inner class),Java语法要求该局部变量必须是final类型。值得一提的是,这里不仅用到了并发式,而且与函数式也密切相关。” “函数式?”逗号奇道。 “不错。”冒号坚定地点着头,“函数式的一个重要特征是:函数是头等公民(first-class citizen),即与其他基本数据类型一样,可以作为传递参数、作为其他函数返回值或与变量名绑定。闭包(closure)便是这样一种函数,并且能保留当初创建时周围的环境变量。以上匿名类本质上是函数serve的包装,经实例化后作为参数传入Thread的构造函数,并且记住了外部类的局部变量customer——这也是为什么它必须是final以保证不被重新赋值的原因。应该说这是一种OO化的闭包形式,预计在Java 7中它的用法会更简洁。” 句号自告奋勇:“我来具体实现serve吧。” 得到冒号的默许,句号在黑板上写下—— private void serve(Customer customer) { // 找一个空闲的接待员 Receptionist receptionist = findReceptionist(); receptionist.receive(customer); receptionist.usher(customer); // 找一个空闲的服务员 Waiter waiter = findWaiter(); waiter.pourTea(customer); List<Order> orders = waiter.write(customer); // 将菜单交给一位厨师 Cook cook = waiter.pass(orders); for (Order order : orders) // 厨师照单做菜 { |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |