随笔 - 78  文章 - 1  评论 - 1766 

  这些日子,注意到很多人对设计模式相当热衷。或许一向如此吧,就像.Net和Java比较那种月经贴。不过昨天看到一篇趣文,不是趣在有新意,趣在上来作者发表的模式宣言:

超级扫盲-什么是设计模式?

  设计模式绝对不是纸上谈兵的知识,光看书就以为自己懂了,那只是井底之蛙之见,设计模式绝对是从实践中来到实践中去的!如果编码经验很少,也不太可能能理解好设计模式,但凡软件设计能力强的人编码功底都是相当扎实的。如果没有能深刻理解面向对象,也不太可能理解好设计模式 

  这个引用一下,就不评论了。只说自己,虽然园子里N个设计模式系列了(偶只看过TerryLee和吕震宇的系列)。眼前有景道不得啊!这里只解决现实问题吧。

  很现实-面试。老经典得让狗嘴长得出象牙的问题-你用过哪些设计模式?

  按一般思维,罗列几个名词,可面试官岂是如此容易打发得了的?接着他挑出一两个追根究底一轮轰炸,对于高手们自然不在话下,兵来将挡水来土淹。偶这种书没看,编码经验又少,又没啥设计能力,只会纸上谈兵的心理素质差劲者,稍不留神就会露出马脚。所以,最好是一下子把对方镇住,免得节外生枝。

  于是偶答道:设计模式是面向对象设计思想在应用中总结出的在不同场合下的具体实践方案。一般来讲,编程语言越高级,对面向对象支持越好,运用设计模式就越容易。比如.Net平台本身,就实现了许多设计模式。

  这时要略停顿一下,面试官一定按捺不住,问“那都有哪些模式呢?”就算义务教学吧,偶滔滔不绝起来:比如项目中添加服务引用,会自动生成服务代理类,实现了典型的代理模式;.Net中对WebRequet、Stream等抽象类的继承扩展,运用了装饰模式;Asp.Net运行时初始化HttpApplication,运用了单例模式;.Net可以通过IEnumerable接口,包含了迭代器模式,而该接口的GetEnumerator方法定义,又是抽象工厂模式的应用……

  轮到面试官受不了了,只好打断你的话,三次皆不例外。“好了好了,那咱们再谈谈比尔盖茨吧,他是属牛还是鸡的呢……?”

posted on 2010-03-19 20:48 小城故事 阅读(2734) 评论(33) 编辑 收藏

 回复 引用 查看   
#1楼 2010-03-19 21:03 | dax.net      
嗯,面试技巧很重要。呵呵。
 回复 引用 查看   
#2楼 2010-03-19 21:17 | Ivony...      
偶从来没问过设计模式这样的傻问题。
 回复 引用 查看   
#3楼 2010-03-19 22:28 | 卡索      
呵呵!受教了...
 回复 引用 查看   
#4楼 2010-03-19 23:01 | chenkai      
hehe ...
 回复 引用 查看   
#5楼 2010-03-19 23:54 | heaiping      
我靠,我是来学东西的,结果做了几个俯卧撑,然后提着满满的一瓶酱油走了
 回复 引用 查看   
#6楼 2010-03-20 00:08 | winter-cn      
楼主面试肯定挂了......

GetEnumerator说成抽象工厂liao......

 回复 引用 查看   
#7楼[楼主] 2010-03-20 09:52 | 小城故事      
@winter-cn
不是抽象工厂,难道是简单工厂?

 回复 引用 查看   
#8楼 2010-03-20 10:01 | winter-cn      
......
这也不是工厂啊

IEnumerable听着怎么都跟工厂搭不上边吧

 回复 引用 查看   
#9楼 2010-03-20 10:29 | winter-cn      
个人认为LZ的回答非但镇不住面试官 碰到稍微懂点设计模式的面试官反而会被追问的很惨
如下问题供楼主参考:

你说语言越高级,对面向对象支持越好,请你说说你对语言“高级”和“低级”的理解

请举几个高级语言面向对象的例子,说说你对他们的评价,如何体现面向对象的好与不好?

你认为设计模式能在LISP、Schema等函数式语言中应用吗?

请说说Net中对WebRequet、Stream等抽象类的继承扩展,是如何运用的装饰模式? 谁是Decorator?谁又是Component接口?

如何获得一个HttpApplication的实例?

HttpApplication的单例模式,在多线程应用中是否会带来问题?

你认为IEnumerable是抽象工厂模式,那么请说说你理解的抽象工厂的意图是什么?

你认为IEnumerable设计的意图是什么,它跟抽象工厂是否一致?

你在项目中哪些场景下,使用了IEnumerable接口,它解决了你什么问题?

 回复 引用 查看   
#10楼 2010-03-20 10:32 | Ivony...      
嗯,事实上所有的这些模式都有问题。

对Stream和WebRequest的派生不是什么模式,这是非常基本的继承。
装饰模式恰恰是不通过派生类来实现的。

另外初始化HttpApplication并不是简单的单例模式。
HttpApplication的初始化是一个非常复杂的过程,绝对不是“单例模式”四个字可以解释清楚的,摘相关代码如下:
    HttpApplication application = null;
    lock (this._freeList)
    {
        if (this._numFreeAppInstances > 0)
        {
            application = (HttpApplication) this._freeList.Pop();
            this._numFreeAppInstances--;
            if (this._numFreeAppInstances < this._minFreeAppInstances)
            {
                this._minFreeAppInstances = this._numFreeAppInstances;
            }
        }
    }
    if (application == null)
    {
        application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
        using (new ApplicationImpersonationContext())
        {
            application.InitInternal(context, this._state, this._eventHandlerMethods);
        }
    }
    return application;


IEnumerator是迭代器模式应该没错,但IEnumerable却不是任何一种工厂模式,因为他生产的不是产品而是工具。

这里的手法其实是自我装饰,不过设计模式本来就很扯,设计的手法成百上千种,根本就不可能概括完全。

 回复 引用 查看   
#11楼[楼主] 2010-03-20 10:37 | 小城故事      
@winter-cn
偶只知道IEnumerable就是一个抽象工厂,因为GetEnumerator规定要创建抽象实例IEnumerator,你要是觉得有问题可以再翻翻定义反驳我。
至于面试的效果,我三次碰到都是如我所说,也很可能你的水平比他们都高。我已经说了,我对设计模式理解也是初级阶段,但.Net本身设计模式中应用的理解,不是凭想像蒙或是网上抄下背出来的。

 回复 引用 查看   
#12楼[楼主] 2010-03-20 10:45 | 小城故事      
@Ivony...
装饰模式比较难说,期待能有更深刻的认识。你对HttpApplication说得对,不仅是单例。
确实,设计模式是一些具体实践方式,还没形成什么金科玉律。

 回复 引用 查看   
#13楼 2010-03-20 10:46 | winter-cn      
@Ivony...
哈哈 很认真嘛

 回复 引用 查看   
#14楼 2010-03-20 10:50 | winter-cn      
引用小城故事:
@winter-cn
偶只知道IEnumerable就是一个抽象工厂,因为GetEnumerator规定要创建抽象实例IEnumerator,你要是觉得有问题可以再翻翻定义反驳我。
至于面试的效果,我三次碰到都是如我所说,也很可能你的水平比他们都高。我已经说了,我对设计模式理解也是初级阶段,但.Net本身设计模式中应用的理解,不是凭想像蒙或是网上抄下背出来的。

其实你如果试图回答我的问题 就会发现IEnumerable跟抽象工厂一点关系都没有。

另外请参看Ivony的回答

 回复 引用 查看   
#15楼 2010-03-20 10:54 | 烙馅饼喽      
@winter-cn
追问了也不见得就答不上来啊?我们可以把问题转向我较擅长的地方,比如说,我在存储过程里用的设计模式,何如?面试官再牛叉,还能所有技术领域都懂啊?呵呵,够胆咱们单挑T-SQL啊

 回复 引用 查看   
#16楼 2010-03-20 10:56 | Ivony...      
设计模式最重要的是意图而不是形式。所以IEnumerable不是任何一种工厂模式,因为其意图与工厂模式是不同的。

事实上纯粹的什么抽象工厂模式很难找,但与工厂相关的东东,你可以找找.NET Framework里面以Factory结尾的类型,它们的职能大体上都是工厂。只不过,大多数是类似于工厂方法模式而非抽象工厂。

与抽象工厂比较相近的可以认为是IDbConnection族的类型,有些时候我们也会自己写IDbProvider用以创建针对某类数据库的Connection、Command和Adaptor,这样的产品系列,就比较吻合抽象工厂模式。

 回复 引用 查看   
#17楼 2010-03-20 10:57 | 烙馅饼喽      
比如说,经典的行专列问题,在SQL2000年代我就忽悠说我用工厂来生成内部SQL...行转列可是有个超级大陷阱的,一般的面试官,只要敢接招,必挂无疑^_^
 回复 引用 查看   
#18楼 2010-03-20 11:00 | Ivony...      
引用烙馅饼喽:
@winter-cn
追问了也不见得就答不上来啊?我们可以把问题转向我较擅长的地方,比如说,我在存储过程里用的设计模式,何如?面试官再牛叉,还能所有技术领域都懂啊?呵呵,够胆咱们单挑T-SQL啊



就算是那个SB的中文翻译也是:
设计模式:可复用面向对象软件的基础

尽管事实上应该翻译成:
设计范例:高复用度面向对象软件设计典范


无论哪种翻译,都有面向对象存在。
除非你研究的是存储过程领域的设计模式。
比如说:
设计模式:存储过程显摆秘籍。

很好,你是独创者,换言之你说啥都是对的。

 回复 引用 查看   
#19楼[楼主] 2010-03-20 11:02 | 小城故事      
@winter-cn
Ivony回答搞不懂,抽象工厂不就是约束如何创建具体工厂吗?创建的当然是工具不是产品,应该是他自己没理解!你倒数第三个问题已经回答了,再答倒数第二个:
IEnumerable意图为了实现迭代器,至于为什么弄成一个抽象工厂我不清楚是否有必要,我只知道它符合抽象工厂的定义。
你可以写个抽象工厂类,和IEnumerable比较一下。

PS:可能我理解错了Ivony的话,Ivony意思应该是IEnumerable是定义生产工具而不是产品的。抱歉!

 回复 引用 查看   
#20楼 2010-03-20 11:06 | 烙馅饼喽      
那就是了,他不是问能否在LISP里实现吗?我说可以在存储过程里实现,不行么?
 回复 引用 查看   
#21楼 2010-03-20 11:06 | 烙馅饼喽      
这可不是显摆,他既然想追问,那我自然要反击
 回复 引用 查看   
#22楼 2010-03-20 11:13 | Ivony...      
引用小城故事:
@winter-cn
Ivony回答搞不懂,抽象工厂不就是约束如何创建具体工厂吗?创建的当然是工具不是产品,应该是他自己没理解!你倒数第三个问题已经回答了,再答倒数第二个:
IEnumerable意图为了实现迭代器,至于为什么弄成一个抽象工厂我不清楚是否有必要,我只知道它符合抽象工厂的定义。



抽象工厂是用Runtime Type决定创建具体产品系列,产品系列的约束是产品抽象基类,工厂行为约束是工厂行为抽象基类。

这个模式的意图园子里之前的文章已经解释的很清楚了,抽象工厂的场景是不知道要多少个产品(或是同系列多个产品)时,直接获取工厂对象而非具体产品对象的手法。

尽管IEnumerable看起来是一个工厂行为的基类,而IEnumerator看起来也是一个工厂产品的基类,从形式上来说完全吻合没有问题。

但问题的关键在于这里的产品是没有意义的东西,我们关注的点恰恰还是工厂本身(IEnumerable对象)。换言之我们根本就不需要产品,而是需要工厂。这个产品的本质又是什么呢?这个产品的本质是工厂的装饰(IEnumerator绝大多数实现是装饰模式)。

也就是所谓的意图不同。

回到实处,讨论微软和四人帮的分歧。在这里,事实上工厂类(容器类)完全可以自己实现IEnumerator接口么(这正是四人帮的愚昧的想法)。所以这里的手法不属于任何设计模式(因为四人帮根本不理解微软),工厂类(容器类)不自己实现IEnumerator接口,而采用自我抛出装饰的方式来实现,是因为考虑到多线程的情况。因为IEnumerator对象只能在一个线程工作,在多线程同时访问就会紊乱。(四人帮似乎从来不搞多线程的,所以我一直觉得设计模式很扯。)

 回复 引用 查看   
#23楼[楼主] 2010-03-20 11:13 | 小城故事      
引用烙馅饼喽:那就是了,他不是问能否在LISP里实现吗?我说可以在存储过程里实现,不行么?

反击效果如何呢?

 回复 引用 查看   
#24楼 2010-03-20 11:15 | 烙馅饼喽      
那就看实际情况喽:)
我只是说,如果遇到这种情况,我就这么干,呵呵
其实,我压根就不懂设计模式


 回复 引用 查看   
#25楼 2010-03-20 11:20 | winter-cn      
引用烙馅饼喽:那就是了,他不是问能否在LISP里实现吗?我说可以在存储过程里实现,不行么?

这是个坑...... 传统的LISP里面是不能实现,或者说无需使用的......
所以回答应该是 设计模式是特定为解决面向对象语言设计问题的经典模式 不适用其它编程范型

另外 炫耀技术不是你的目的 你需要找出你身上让面试官感兴趣的地方 你给一个专门做Java的人讲T-SQL是在浪费你自己的面试时间......

 回复 引用 查看   
#26楼[楼主] 2010-03-20 11:22 | 小城故事      
@Ivony...
我还是坚持IEnuerable是用抽象工厂理念设计的,只是我们没有创建具体产品,在实现GetEnumrator方法时,.Net已经为我们创建好了一个。如果你有疑问,我想问,定义一个string[] strList = {...};strList.GetEnumrator()返回的是什么呢?是没有意义的东西吗?

 回复 引用 查看   
#27楼 2010-03-20 11:23 | 烙馅饼喽      
我只是认为,面试官如果故意想要问倒被面试的人,那是很简单的,比较是出题的人么。比如那个httpApplication,难道说没去看过.net源码的人就都不合格??
如果遇到这样的题,那我就认为这纯粹是故意刁难,说到底,大家搞编程的谁没有比较擅长的领域啊?能反击最好,反击不了,就面试下一家咯,又没啥损失。

 回复 引用 查看   
#28楼 2010-03-20 11:30 | winter-cn      
引用小城故事:
@winter-cn
Ivony回答搞不懂,抽象工厂不就是约束如何创建具体工厂吗?创建的当然是工具不是产品,应该是他自己没理解!你倒数第三个问题已经回答了,再答倒数第二个:
IEnumerable意图为了实现迭代器,至于为什么弄成一个抽象工厂我不清楚是否有必要,我只知道它符合抽象工厂的定义。
你可以写个抽象工厂类,和IEnumerable比较一下。

PS:可能我理解错了Ivony的话,Ivony意思应该是IEnumerable是定义生产工具而不是产品的。抱歉!

其实关键还是Ivony所说 设计模式最重要的是意图而不是形式。

设计模式并不存在所谓定义,说起来设计模式中每个模式的第一项就是"意图",没有意图,就谈不上应用模式。

类结构一样不一定就符合某种模式 设计模式中的类,都是有特定语意的。

所以为什么我在问"意图",你忽略了工厂模式的意图,所以导致你错误地认定IEnumerator是抽象工厂或者其它工厂模式。

其实GetXXXXX返回一个对象这种方式相当常见,但是事实上应用工厂模式的情况很少。

 回复 引用 查看   
#29楼 2010-03-20 11:40 | Ivony...      
引用小城故事:
@Ivony...
我还是坚持IEnuerable是用抽象工厂理念设计的,只是我们没有创建具体产品,在实现GetEnumrator方法时,.Net已经为我们创建好了一个。如果你有疑问,我想问,定义一个string[] strList = {...};strList.GetEnumrator()返回的是什么呢?是没有意义的东西吗?



呵呵,其实这种问题去较真是无所谓的。我一直认为设计模式本来就是很扯的,所以我面试的时候也不会问。面试的时候去跟面试官大谈四人帮与微软的理念分歧,结果恐怕都是扫地出门。所以我觉得你这样去理解,也是可以的。

总结一下,设计模式的意图非常重要,抽象工厂模式的意图与IEnumerable的设计其实是南辕北辙的,只是形式上相似而已。我们不禁要问,为什么四人帮的那本书没有包含这种意图的设计。我想两个原因,一是设计手法成百上千,绝对不可能一一概括,所以二十三种设计模式本身就很扯。二是四人帮似乎从来就不考虑多线程的,尽管可以借口说与时代有关,但我更乐意理解为这四个家伙根本就不写多线程程序。如果不考虑多线程的因素,从四人帮的思维出发,我们会觉得里完全是多此一举。而微软的这种设计,尽管可能还有其他因素的考虑(例如将功能分散到不同类型,避免类型爆炸或是单一职责原则的细处遵循,或是使得包含内部容器的容器不必写纯代理方法而是直接暴露内部容器的GetEnumerator),但多线程恐怕是决定性的因素。

 回复 引用 查看   
#30楼 2010-03-20 11:52 | winter-cn      
引用烙馅饼喽:
我只是认为,面试官如果故意想要问倒被面试的人,那是很简单的,比较是出题的人么。比如那个httpApplication,难道说没去看过.net源码的人就都不合格??
如果遇到这样的题,那我就认为这纯粹是故意刁难,说到底,大家搞编程的谁没有比较擅长的领域啊?能反击最好,反击不了,就面试下一家咯,又没啥损失。

其实每个问题都有背后的意义 你不去了解就会觉得是刁难
问HttpApplication的创建过程是因为 它并非单例模式 而问WebRequet、Stream,则是因为他们没有涉及到装饰器模式

其实要刁难人 根本无需这样问
我以前某次面试微软的vendor 因为前一位面试的人说结果非常不错 所以准备的问题比较难 问了一小时 一大半问题没答出来 当然最后还是让他通过了

 回复 引用 查看   
#31楼 2010-03-20 12:53 | forhells      
不懂什么是面向对象,什么是设计模式。
 回复 引用 查看   
#32楼[楼主] 2010-03-20 13:42 | 小城故事      
@Ivony...
我觉得IEnumerable中抽象工厂模式再明显不过了,你一直说设计模式的意图,看来确是我还没理解的东西,先记住这么个东西吧。至于IEnumerable,不管它是抽象工厂还是像抽象工厂,这样设计用意何在,我会继续研究的。

 回复 引用 查看   
#33楼 2010-03-20 16:33 | 深山老林      
哈哈,这样的问题还真不好回答。
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1690105 H5+KQTKUv6k=