Spiga

对于一道面试题的一点看法

2008-07-14 16:21 by GUO Xingwang, 2645 visits, 收藏, 编辑

      最近在逛csdn时遇到个关于一道面试题的讨论,觉得很有趣.说的是有位朋友在面试时被问到”电饭煲是如何知道饭已熟了的”问题.(原文和讨论http://topic.csdn.net/u/20080709/17/5262b09f-9d3a-4294-a27c-ac972e2cc34c.html),对于这个问题每个人都有不同的看法.在这里,我主要想谈一下自己对这个问题的一点看法.

             我觉得面试官出的这个问题是很有水平的.个人觉得面试官好像在考查应聘者的分析问题和解决问题的能力,在考应聘者的抽象思维,更具体的就是在考应聘者设计模式的应用.面试官想通过这道问题看出应聘者对待问题的一种思维方式.我的分析是这样的(灵感来源于张子阳的大作 <<C# 中的委托和事件>> 中的热水器的案例):我认为这就是一个观察者模式的应用,我们可以简单把电饭煲看成由加热器Heater和控制器Controller(具体构成可能远远不止这两个)两个关键部件组成.加热器只负责加热,不能进行控制.而控制器主要负责使电饭煲跳闸或置于保温状态,它不能加热.在具体了解我的看法之前,我们先来看一下观察者模式的原型,观察者设计模式中主要包括如下两类对象

Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在这个案例中,加热器就是一个监视对象,它包含着其他对象所感兴趣的内容,那就是temprature字段,假设当这个字段的值到101时,会把数据发给监视它的对象。置于为什么会说假设温度达到101时呢,这里也涉及到一些高中物理方面的知识.加热的对象是水和米的混合物,开始时混合物从某一较低的温度上升,直到上升到100摄氏度(标准大气压下)时就不会上升了,这时水处于沸腾状态(气化),慢慢水干以后,剩下的米饭温度会继续上升直到101度发出通知,之后监视者进行一些处理.

Observer:监视者,它监视着Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本案例中,Observer就是控制器,它采取的行动就是使电饭煲处于保温状态或跳闸。

下面就用观察者模式模拟一下电饭煲的工作吧:

加热器(Subject):

 1public class Heater
 2    {
 3        private string _name;
 4        private int _temperature;
 5
 6        //监视者列表
 7        private ArrayList _observers = new ArrayList();
 8
 9        public Heater(string name, int temperature)
10        {
11            _name = name;
12            _temperature = temperature;
13        }

14
15        //增加监视者
16        public void AttachListener(Controller observer)
17        {
18            _observers.Add(observer);
19        }

20
21        //删除监视者
22        public void DetachListener(Controller observer)
23        {
24            _observers.Remove(observer);
25        }

26
27        //煮米饭
28        public void BoilRice()
29        {
30            for (int i = _temperature; i <= 101; i++)
31            {
32                _temperature = i;
33                Thread.Sleep(1);//为观察结果方便
34                Console.WriteLine("当前温度{0},正在上涨!", _temperature);
35
36                //当温度超过100时发出通知
37                if (_temperature > 100)
38                {
39                    foreach (Controller c in _observers)
40                    {
41                        c.Shutdown();
42                    }

43                }

44            }

45        }

46
47        public string Name
48        {
49            get return _name; }
50            set { _name = value; }
51        }

52
53        public int Temperature
54        {
55            get return _temperature; }
56            set { _temperature = value; }
57        }

58    }

控制器(Observer):

 1public class Controller
 2    {
 3        private string _name;
 4        private Heater _sender;
 5        
 6        public Controller(string name, Heater sender)
 7        {
 8            _name = name;
 9            _sender = sender;
10        }

11
12        //监视者处理通知
13        public void Shutdown()
14        {
15            Console.WriteLine("我是{0},{1}目前的温度为{2}",  _name,  _sender.Name, _sender.Temperature);
16        }

17    }

测试主程序:

 1class MainApp
 2    {
 3        static void Main()
 4        {
 5            Console.Read();
 6
 7            Heater h = new Heater("加热器"80);
 8
 9            h.AttachListener(new Controller("控制器", h));
10
11            h.BoilRice();
12
13            Console.Read();
14        }

15    }

输出结果:
 

这是我对电饭煲工作原理的理解,由于每个人的世界观是不同的,对同一事物的理解可能千差万别.不知道大家是怎么看的!
 

总结:为什么我们要面向对象设计,为什么要使用设计模式.主要就是面向对象设计可以非常好的描述出事物本来的面目.事物的存在就有它存在的理由,这是自然规律,所以按照事物本身的特征去描述它自然也就是合理的.软件设计就是如此.
希望这篇文章能给大家在应用设计模式和解决问题方面带来收获!

为了方便还是附上源码:/Files/Thriving-Country/Observer20080714/Observer.rar

【作者】:GUO Xingwang
【来源】:http://thriving-country.cnblogs.com/ 
     本文版权归作者和博客园共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
Add your comment

53 条回复

  1. #1楼 2008年的梦想      2008-07-14 16:25
    顶一下。
     回复 引用 查看   
  2. #2楼 yefang_world      2008-07-14 16:32
    “事物的存在就有它存在的理由,这是自然规律,所以按照事物本身的特征去描述它自然也就是合理的.软件设计就是如此.”
    支持楼主!
     回复 引用 查看   
  3. #3楼 Jim~      2008-07-14 16:59
    只有在气压达到一定程度,温度达到并保持一定程度和时间段,米饭才能熟,不然不是夹生的就是稀饭了哦。。。。
     回复 引用 查看   
  4. #4楼[楼主] thriving.country      2008-07-14 17:04
    --引用-------------------------------------------------- Jim~: 只有在气压达到一定程度,温度达到并保持一定程度和时间段,米饭才能熟,不然不是夹生的就是稀饭了哦。。。。 --------------------------------------------------------

    确实是,我做米饭有时就不熟,后来有经验了就多放些水,本质上电饭煲也不知道米饭到底熟没熟!哈哈
     回复 引用 查看   
  5. #5楼 yuyoo      2008-07-14 17:09
    楼主是一个有心的人,对问题的分析很到位。谢谢楼主分享
     回复 引用 查看   
  6. #6楼 wfa[未注册用户]2008-07-14 18:00
    其实电饭煲,可能是测试饭水混合物的电阻,水少到一定程度了,电阻就大了,电饭煲就可以判断饭熟了。如果水加少了,自然是夹生的。
     回复 引用   
  7. #7楼 wfa[未注册用户]2008-07-14 18:04
    标准答案:

    电饭煲的温度控制器中有一块磁钢,它的温度转折点是103-105度(高于此温度时磁钢失去磁性);当电饭锅中有水时,它的温度不可能超过100度,一旦煮干,电饭锅中的温度就会超过100度,当锅内温度达到103-105度时,磁钢就失去磁性,原先被它吸住的另件松开,在弹簧作用下,断开电饭煲的升温电源,保留保温电源,再焖15分钟.饭就熟了。
     回复 引用   
  8. #8楼[楼主] thriving.country      2008-07-14 18:07
    --引用-------------------------------------------------- wfa: 标准答案: 电饭煲的温度控制器中有一块磁钢,它的温度转折点是103-105度(高于此温度时磁钢失去磁性);当电饭锅中有水时,它的温度不可能超过100度,一旦煮干,电饭锅中的温度就会超过100度,当锅内温度达到103-105度时,磁钢就失去磁性,原先被它吸住的另件松开,在弹簧作用下,断开电饭煲的升温电源,保留保温电源,再焖15分钟.饭就熟了。 --------------------------------------------------------

    很好,我没有研究过,现在终于明白了!
     回复 引用 查看   
  9. #9楼 QUZHENG[未注册用户]2008-07-14 18:11
    为什么要用ARRAYLIST 做控制器啊,为什么不直接定义一个变量啊
     回复 引用   
  10. #10楼 金金      2008-07-14 18:14
    顶!
     回复 引用 查看   
  11. #11楼 金色海洋(jyk)      2008-07-14 18:26
    电饭煲问米饭:喂,老兄,熟没?

    ......

    没有回应的话,就说明已经熟了。
     回复 引用 查看   
  12. #12楼 zzticzh1[未注册用户]2008-07-14 18:45
    @金色海洋(jyk)

    这个回答很好!
     回复 引用   
  13. #13楼 asmx[未注册用户]2008-07-14 19:08
    比ML简单多了。
     回复 引用   
  14. #14楼[楼主] thriving.country      2008-07-14 19:08
    @QUZHENG
    因为观察者模式中的观察者可能有很多,控制器只是其中的一个!
     回复 引用 查看   
  15. #15楼 老刀把子      2008-07-14 19:36
    打开盖就知道了
     回复 引用 查看   
  16. #16楼 freewolf[未注册用户]2008-07-14 19:45
    问个1+1等于几也要认真的思考半天吗。再说啦想知道什么就问什么,干嘛还要拐弯抹角的
     回复 引用   
  17. #17楼 向世界出发      2008-07-14 20:37
    @老刀把子
    你不会是WOW里面大地工会的“老刀把子”吧?
     回复 引用 查看   
  18. #18楼 peaceful_fish      2008-07-14 22:34
    非常好的帖子~~~
    我接触"C++"时间不长,它帮我更好了体悟了"面向对象"
     回复 引用 查看   
  19. #19楼 怪怪      2008-07-15 05:08
    文章很好, 例子也还合适, 不过:

    “为什么我们要面向对象设计,为什么要使用设计模式.主要就是面向对象设计可以非常好的描述出事物本来的面目.事物的存在就有它存在的理由,这是自然规律,所以按照事物本身的特征去描述它自然也就是合理的.软件设计就是如此.”

    这句话不知道害了多少人。 换几个例子, 比如看看那本《敏捷软件开发》C#版中咖啡壶那一章就知道了。 说实话,对面向对象越熟悉, 越不会认为和现实世界对应是好的面向对象手法。

    的确, 很多面向对象的设计结果和现实事物差不多,而且非常直白。 说实话, 这很难说是好的抽象思维, 而仅仅是一种具体化描述。 这种描述之所以看起来很合理, 不过是因为在这个问题上暂且不需要高级的抽象。

    在这一样一个设计中, 即使使用了设计模式之类的手法, 也不会真正得到面向对象的好处, 这些样本, 如果重构为精心安排的面向过程式的描述, 也会是干净漂亮的。

    呃, 又多嘴了, 撤走。
     回复 引用 查看   
  20. #20楼 xiaotie      2008-07-15 07:02
    用得着这么复杂吗?

    while(Temperature<=100)
    {
    Heat();
    }
     回复 引用 查看   
  21. #21楼[楼主] thriving.country      2008-07-15 09:12
    @xiaotie

    确实可以简单,甚至还可以简单.这里主要体现在模式的应用上,Demo可能很简单,但是主要体现的是设计的思路问题!谢谢
     回复 引用 查看   
  22. #22楼[楼主] thriving.country      2008-07-15 09:17
    @怪怪

    这个问题好像涉及到到了面向过程设计与面向对象设计的比较问题!我的观点是这样的,如果您具有很好的面向对象设计的思想,各种知识可以灵活运用的话,面向对象设计会更好,当然面向过程设计有它的好处!
    我们可能很容易理解面向对象,但是要灵活应用面向对象还是不容易的!
     回复 引用 查看   
  23. #23楼 谁说的[未注册用户]2008-07-15 09:25
    标准论
    饭熟需要有一个标准,究竟是90度还是101度。
    谁来确定这个标准?是电饭锅还是人?
    当然是人,电饭锅确定100度是人经过了大量的实验才完成的。
    所以电饭锅应该 有一个投票选项
    第一次,电饭锅设定90度,煮饭,结果人投票为-1分
    第二次,电饭锅设定91度,煮饭,结果人投票为0分
    ...
    第n次,电饭锅设定为100度,结果满意度最大,所以电饭锅认定100度就是饭熟的温度。
     回复 引用   
  24. #24楼 雅阁布      2008-07-15 09:38
    分析的太棒了!!!
     回复 引用 查看   
  25. #25楼 Tony Zhou      2008-07-15 09:47
    就是想问observe模式咯,想问你就说嘛
     回复 引用 查看   
  26. #26楼[楼主] thriving.country      2008-07-15 09:55
    @谁说的

    分析的有理,从另一个角度可以这样解释!
     回复 引用 查看   
  27. #27楼[楼主] thriving.country      2008-07-15 09:57
    @Tony Zhou

    不知道到底想问什么,我也是猜测!这个东西就没有标准答案!我这里主要是发表一下自己的看法!
     回复 引用 查看   
  28. #28楼 amingo      2008-07-15 10:04
    Heater 为什么有监视列表,加热器要监视谁?

    heater引用了controller
    controller又引用了heater
     回复 引用 查看   
  29. #29楼[楼主] thriving.country      2008-07-15 10:12
    @amingo


    1.监视列表是所有监视它的对象集合.
    2.控制器监视加热器,控制器需要注册监视,就需要在加热器的监视列表中加入一个.
    3.置于引用问题可以把它们设计成接口,之后使用继承实现,但是这里还是一个观察者模式.
    谢谢
     回复 引用 查看   
  30. #30楼 amingo      2008-07-15 10:14
    --引用--------------------------------------------------
    thriving.country: @amingo


    1.监视列表是所有监视它的对象集合.
    2.控制器监视加热器,控制器需要注册监视,就需要在加热器的监视列表中加入一个.
    3.置于引用问题可以把它们设计成接口,之后使用继承实现,但是这里还是一个观察者模式.
    谢谢
    --------------------------------------------------------

    Controller 中就不应该有heater
     回复 引用 查看   
  31. #31楼 amingo      2008-07-15 10:15
    如果电饭包中再加一个加湿器 难道还要在controller中加一个加湿器
     回复 引用 查看   
  32. #32楼 amingo      2008-07-15 10:16
    如果controller是观察者 那就不应该对heater有控制作用,只是接收事件通知。
     回复 引用 查看   
  33. #33楼[楼主] thriving.country      2008-07-15 10:19
    --引用--------------------------------------------------
    amingo: 如果电饭包中再加一个加湿器 难道还要在controller中加一个加湿器
    --------------------------------------------------------
    3.置于引用问题可以把它们设计成接口,之后使用继承实现,但是这里还是一个观察者模式.

    这个可能不是好的设计,但是它体现的是观察者模式,当初写Demo时考虑到您说的问题了,后来我想合适算了,我想说的是设计模式而不是松耦合,设计模式和松耦合没有必然的关系吧!
     回复 引用 查看   
  34. #34楼 amingo      2008-07-15 10:20
    我想说的是设计模式而不是松耦合,设计模式和松耦合没有必然的关系吧!


    设计模式为了什么?
     回复 引用 查看   
  35. #35楼 火无极      2008-07-15 10:22
    这个问题真是好,比得上MS的面试题了.
     回复 引用 查看   
  36. #36楼 随风逝去(叶进)      2008-07-15 10:22
    --引用--------------------------------------------------
    xiaotie: 用得着这么复杂吗?

    while(Temperature&lt;=100)
    {
    Heat();
    }
    --------------------------------------------------------
    nice
     回复 引用 查看   
  37. #37楼[楼主] thriving.country      2008-07-15 10:26
    @amingo
    设计模式一般可以解藕,如果这样问的话,我还想说设计模式是什么?
    设计模式在应用时就有很多违反设计原则的!
     回复 引用 查看   
  38. #38楼 amingo      2008-07-15 10:27
    "我想说的是设计模式而不是松耦合,设计模式和松耦合没有必然的关系吧!"

    "设计模式一般可以解藕"

    前后矛盾!
     回复 引用 查看   
  39. #39楼 amingo      2008-07-15 10:27
    --引用--------------------------------------------------
    amingo: 如果controller是观察者 那就不应该对heater有控制作用,只是接收事件通知。
    --------------------------------------------------------
     回复 引用 查看   
  40. #40楼[楼主] thriving.country      2008-07-15 10:33
    @amingo

    这个问题到此为止,如果您认为这是一对矛盾我也没什么好说的!谢谢关注!
     回复 引用 查看   
  41. #41楼 amingo      2008-07-15 10:34
    自始自终都没回答:如果controller是观察者 那就不应该对heater有控制作用,只是接收事件通知。
     回复 引用 查看   
  42. #42楼[楼主] thriving.country      2008-07-15 10:35
    @amingo

    好像没有控制作用吧 只是引用而已 说白了还是耦合的问题!
     回复 引用 查看   
  43. #43楼 Ivony[未注册用户]2008-07-15 10:36
    多么垃圾的面试题。

    最原始的电饭煲用的温控设备是一块双金属片,即用两种金属粘贴而成,由于两种金属热胀冷缩系数不同,双金属片遇热就会卷曲,
     回复 引用   
  44. #44楼 amingo      2008-07-15 10:38
    引用了就不是观察者了。
     回复 引用 查看   
  45. #45楼[楼主] thriving.country      2008-07-15 10:43
    @amingo

    C#的事件处理的sender是一个Object,但是使用sender时一般是不是也要cast你想要的类型才能使用!那您说这是不是一个观察者模式啊?
     回复 引用 查看   
  46. #46楼 amingo      2008-07-15 10:45
    你好好看看观察者的类图吧,看看观察者需不需要引用被观察着。
     回复 引用 查看   
  47. #47楼[楼主] thriving.country      2008-07-15 10:50
    @amingo

    不说了这个了!
    我的总结:模式的应用在于灵活,不是说完全符合类图的就是观察者模式,代码是思想的体现,而不仅仅是写给机器的!当然类图讲的是标准的!
     回复 引用 查看   
  48. #48楼[楼主] thriving.country      2008-07-15 10:55
    @amingo

    这里有一个观察者模式,您可以研究一下

    http://www.dofactory.com/Patterns/PatternObserver.aspx
     回复 引用 查看   
  49. #49楼 amingo      2008-07-15 10:55
    --引用--------------------------------------------------
    thriving.country: @amingo

    不说了这个了!
    我的总结:模式的应用在于灵活,不是说完全符合类图的就是观察者模式,代码是思想的体现,而不仅仅是写给机器的!当然类图讲的是标准的!
    --------------------------------------------------------

    --------------------------------------------------
    amingo: 如果电饭包中再加一个加湿器 难道还要在controller中加一个加湿器。
    --------------------------------------------------------


    加一个加湿器,如何体现你的灵活
     回复 引用 查看   
  50. #50楼 amingo      2008-07-15 10:56
    --引用--------------------------------------------------
    thriving.country: @amingo

    这里有一个观察者模式,您可以研究一下

    <a href="http://www.dofactory.com/Patterns/PatternObserver.aspx" target="_new">http://www.dofactory.com/Patterns/PatternObserver.aspx</a>
    --------------------------------------------------------


    我觉得你看看 比较适合。
     回复 引用 查看   
  51. #51楼[楼主] thriving.country      2008-07-15 10:57
    @amingo

    希望通过谈论我们都可以从中得到收获!谢谢关注!
     回复 引用 查看   
  52. #52楼[楼主] thriving.country      2008-07-15 10:58
    @amingo

    请看一下代码实现中的引用问题!
     回复 引用 查看   
  53. #53楼 amingo      2008-07-15 11:05
    --引用--------------------------------------------------
    amingo: --引用--------------------------------------------------
    thriving.country: @amingo

    不说了这个了!
    我的总结:模式的应用在于灵活,不是说完全符合类图的就是观察者模式,代码是思想的体现,而不仅仅是写给机器的!当然类图讲的是标准的!
    --------------------------------------------------------

    --------------------------------------------------
    amingo: 如果电饭包中再加一个加湿器 难道还要在controller中加一个加湿器。
    --------------------------------------------------------


    加一个加湿器,如何体现你的灵活

    --------------------------------------------------------
     回复 引用 查看