补仲山公园之衮,虽曲尽于巧心,和傅说之羹,实难调于众口!!!it is hard to please

设计模式随笔-让众口不再难调
设计模式随笔-让众口不再难调
[摘要:同心协力出自宋欧阳建《回田录》卷一:补仲山之衮,虽直尽于巧心;战傅道之羹,真易调于寡心。其本意是大家的口胃分歧,很易做出一种饭菜使全部的人皆觉得好吃。寡心是不是实的]
&众口难调&出自宋&欧阳修《归田录》卷一:&补仲山之衮,虽曲尽于巧心;和傅说之羹,实难调于众口。&其原意是各人的口味不同,很难做出一种饭菜使所有的人都感到好吃。众口是否真的难调呢?其实有个不错的办法可以解决众口难调的问题,那就是吃&自助餐&。
面对众口难调的问题去吃&自助餐&已经不是什么新鲜事,承办一个几百人、几千人的会议往往采用的都是自助餐的方式,让来宾各取所需,这就是所谓的以不变应万变。用更通俗的话来说,就是&东西都在这儿,自己看着办吧&。
在 程序设计中解决这种众口难调的问题用的就是Visitor模式。在这里&众口难调&是指很难设计出一组对象(一桌饭菜)符合每个调用者的需要(口味),因 为你根本就无法预料到这组对象的访问者是谁,有什么样的调用请求,访问什么样的数据。那么对付众口难调的方法&以不变应万变&在Visitor模式中就是 指让一桌饭菜从你面前过,自己看着办就行了。
当然这里也有个先决条件,那就是你对每样饭菜都有一定的了解,自己才能做出选择。否则可能会 瞪着一盘摆满小石子的盘子不知所措。反过来说,饭菜不需要知道来这里就餐的人的口味是什么,只管放出来让客人看着办就行了。这样,顾客和饭菜之间是不均衡 的。顾客必须&有备而来&,但饭菜却对顾客却&一视同仁&。
{ &&public&abstract&void&VisitCoffee(Coffee&c); &&public&abstract&void&VisitMeat(Meat&m); &&public&abstract&void&VisitVegetable(Vegetable&v); }
&ZhangSan&:&Visitor
{ &&public&override&void&VisitCoffee(Coffee&c) &&{ &&&&Console.Write(&&{0}:&Take&a&cup&of&{1},&&,this,&c); &&&&c.AddMilk(); &&&&c.AddSugar(); &&&&Console.WriteLine(); &&}
&&public&override&void&VisitVegetable(Vegetable&v) &&{ &&&&Console.WriteLine(&&{0}:&Take&some&{1}&,&this,&v&); &&}
&&public&override&void&VisitMeat(Meat&m) &&{ &&&&Console.WriteLine(&&I&don't&want&any&meat!&); &&} }
&LiSi&:&Visitor
{ &&public&override&void&VisitCoffee(Coffee&c) &&{ &&&&Console.Write(&&{0}:&Take&a&cup&of&{1},&&,this,&c); &&&&c.AddSugar(); &&&&Console.WriteLine(); &&}
&&public&override&void&VisitVegetable(Vegetable&v) &&{ &&&&Console.WriteLine(&&{0}:&Take&some&{1}&,&this,&v&); &&}
&&public&override&void&VisitMeat(Meat&m) &&{ &&&&Console.WriteLine(&&{0}:&Take&some&{1}&,&this,&m&); &&} }
{ &&abstract&public&void&Accept(&Visitor&visitor&); }
&Coffee:&Food&&
{ &&override&public&void&Accept(&Visitor&visitor&) &&{ &&&&visitor.VisitCoffee(&this&); &&}
&&public&void&AddSugar() &&{ &&&&Console.Write(&add&sugar.&&);&&& &&}
&&public&void&AddMilk() &&{ &&&&Console.Write(&add&milk.&&);&&& &&} }
&Meat:&Food&&
{ &&override&public&void&Accept(&Visitor&visitor&) &&{ &&&&visitor.VisitMeat(&this&); &&} }
&Vegetable:&Food&&
{ &&override&public&void&Accept(&Visitor&visitor&) &&{ &&&&visitor.VisitVegetable(&this&); &&} }
&BuffetDinner
{ &&private&ArrayList&elements&=&new&ArrayList();
&&public&void&Attach(&Food&element&) &&{ &&&&elements.Add(&element&); &&}
&&public&void&Detach(&Food&element&) &&{ &&&&elements.Remove(&element&); &&}
&&public&void&Accept(&Visitor&visitor&) &&{ &&&&foreach(&Food&f&in&elements&) &&&&&&f.Accept(&visitor&); &&} }
{ &&public&static&void&Main(&string[]&args&) &&{ &&&&BuffetDinner&b&=&new&BuffetDinner(); &&&&b.Attach(new&Coffee()); &&&&b.Attach(new&Vegetable()); &&&&b.Attach(new&Meat());
&&&&ZhangSan&z&=&new&ZhangSan(); &&&&LiSi&l&=&new&LiSi();
&&&&b.Accept(&z&); &&&&Console.WriteLine(&----------------------&); &&&&b.Accept(&l&); &&} }
但 是,Visitor模式中所蕴涵的思想绝非一个众口难调的例子所能完全表达的。其中还有&条件外置&(我起的名字)的含义在里面(应当归纳到&Find what vary and encapsulate it&的范畴,是我对这句话的理解),也就是说将条件判断从一个类中抽取出来,或交由专门的对象进行处理,或通过配置文件由用户手工控制。说白了就是做 成&活&的。这种&条件外置&往往离不开多态的帮忙。面向对象中多态性是说,可以将子类型对象赋值给父类型对象,如果子类型复写了父类型的某个方法,那么 当调用父类型对象的此方法时,自动转而调用子类型复写后的方法。条件外置在众多的模式中都有体现:
比如在简单工厂模式中,我们需要判断类型,然后进行加工,如下:
&Light&Create(
&LightType)
{ &&&if(LightType&==&&Bulb&) &&&&&&return&new&BulbLight(); &&&else&if(LightType&==&&Tube&) &&&&&&return&new&TubeLight(); &&&else &&&&&&return&null; }
我们就可以让BulbLight与TubeLight共同继承自Light,再加上一个与之相对应的工厂架构,于是条件便外置到了客户端的手中:
{ &&&Creator&c&=&new&BulbCreator(); &&&Light&l&=&c.factory(); &&& &&&l.TurnOn(); &&&l.TurnOff(); &&&}
如果你想生产什么样子的灯泡就给 Creater c 赋值什么类型的工厂就行了。有人可能还会问,那什么时候使用什么类型的工厂不还是要进行条件判断吗,对了,条件外置后总还是要有人处理的,只不过不在Factory里面,也不在Light里面。你可以集中管理,也可以用配置文件,总之保证了系统绝大多数模块的稳定性。
另外,在策略模式的案例中,如果没有应用&策略模式&,那么我们也必须在业务对象中使用一个长长的If结构,判断何时使用哪个策略。但是借助多态性将&条件外置&后,便将判断控制权交由其他类进行处理,使得业务对象更加稳定。
至 于到底将条件放到什么地方有很多解决办法,其一是放到一个专门的类中,这便应了《Design Pattern Explained》一书中的&Find what vary and Encapsulate it.&这句话,发现变化的东西并且将其封装起来。其二,就是外置成基于XML或纯文本的配置文件,随时可以方便的进行修改。如果愿意,甚至可以编写一个 图形化配置工具实现这一功能。
但是条件外置带来的&负&面影响便是需要&Design to Interface(针对接口或抽象编程)&。针对抽象编程增加了系统的稳定性,提高了可扩展性,并且让用户只与抽象打交道,恰好也应用了&最小知识原 则&。但这对于必须了解对象类型的系统却是个灾难。Visitor模式便是在这个灾难中成活下来的一个很好的例子。虽然还有些争议,但解决的已经是很好 了。
那么在Visitor模式中又是如何将&条件外置&的呢?这个外置工作恐怕比起前两种类型要复杂一些,用到了双重分派(Double Dispatch),所以我们还要从头说起。先让我们现看看没有用Visitor模式的&众口难调&的例子。
{ &&public&virtual&void&Visit(ArrayList&dinner) &&{ &&&&foreach(object&f&in&dinner) &&&&{ &&&&&&if(f&is&Coffee) &&&&&&&&VisitCoffee((Coffee)f); &&&&&&else&if(f&is&Vegetable) &&&&&&&&VisitVegetable((Vegetable)f); &&&&&&else&if(f&is&Meat) &&&&&&&&VisitMeat((Meat)f); &&&&&&else &&&&&&{ &&&&&&&&//&do&nothing &&&&&&} &&&&} &&}
&&protected&virtual&void&VisitCoffee(Coffee&c){} &&protected&virtual&void&VisitVegetable(Vegetable&v){} &&protected&virtual&void&VisitMeat(Meat&m){} }
&ZhangSan&:&Visitor
{ &&protected&override&void&VisitCoffee(Coffee&c) &&{ &&&&Console.Write(&&{0}:&Take&a&cup&of&{1},&&,this,&c); &&&&c.AddMilk(); &&&&c.AddSugar(); &&&&Console.WriteLine(); &&}
&&protected&override&void&VisitVegetable(Vegetable&v) &&{ &&&&Console.WriteLine(&&{0}:&Take&some&{1}&,&this,&v&); &&}
&&protected&override&void&VisitMeat(Meat&m) &&{ &&&&Console.WriteLine(&&I&don't&want&any&meat!&); &&} }
{ &&public&void&AddSugar() &&{ &&&&Console.Write(&add&sugar.&&);&&& &&}
&&public&void&AddMilk() &&{ &&&&Console.Write(&add&milk.&&);&&& &&} }
&Vegetable
{ &&private&static&ArrayList&dinner&=&new&ArrayList();
&&public&static&void&Main(&string[]&args&) &&{ &&&&dinner.Add(new&Coffee()); &&&&dinner.Add(new&Vegetable()); &&&&dinner.Add(new&Meat());
&&&&ZhangSan&z&=&new&ZhangSan();
&&&&z.Visit(dinner); &&} }
在这个例子中,各类食物没有公共父类,所以顾客在Visit的时候,必须将各类食物视作object,然后进行类型判断,再分别进行处理,处理时还不要忘了进行类型转换。长长的If结构会给系统引入很多不必要的麻烦,降低了系统的扩展性。
下 面我对它应用条件外置:为了利用多态性,我们需要给条件中出现过的咖啡、蔬菜、肉赋予一个公共的父类&食物&。但这对我们这个例子这似乎是远远不够的。因 为我们的顾客要&看菜吃饭&,如果利用多态性隐藏了类型信息,只针对抽象&食物&编程的化,我们便失去了&看菜吃饭&的功能,我想这是谁也不希望发生的事 情。因此,我们唯一的方法就是多态后再进行&回调&,让每个具体类(咖啡、蔬菜、肉)自己报上名来,并且自己主动&回调&Visitor中与类型相关的方 法。这样,Visitor只需撒下天罗地网,静待食物找上门来。这便是我对双重分派的一个认识。双重分派利用多态和回调消除了条件判断(这里没有外置条 件),但也引入了一些新的问题:那就是当食物扩展时(比如说加入米饭),必须修改Visitor的天罗地网以提供米饭的回调函数,如果继承自 Visitor的类很多的化,这个系统就变得脆弱起来。其实这也是我在后面要讨论的问题。
Visitor模式的的脆弱在于每个 Visitor必须对所有它要访问的对象有个清晰的了解,一旦增加新类型对象,导致每个Visitor都必须发生变化。另外所有Element(在这个例 子中是指具体食物)在进行回调的时候,也必须清楚回调的是Visitor的什么方法,方法名是什么等等,造成类与类之间耦合过于紧密。有没有更好的办法 呢?我这里说说我的思路:
我的解决办法是二次利用多态性,并辅以模板方法模式(其实算不上模板方法,充其量算个缺省实现罢了)。C#中的 多态性分成两个层面,一个是我们说的继承多态性,另外一个就是方法多态性。方法多态性是指某个类可以包含多个同名方法,但签名不同。系统在进行调用时自动 匹配签名最相近的一个方法。我们平时使用最多的Console.WriteLine方法便有19个签名各异的&多态&。改造后的Visitor代码如下:
{ &&public&virtual&void&Visit(Meat&m) &&{&this.Visit((object)m);&}
&&public&virtual&void&Visit(Vegetable&v) &&{&this.Visit((object)v);&}
&&public&virtual&void&Visit(Coffee&c) &&{&this.Visit((object)c);&}
&&public&void&Visit(Object&f) &&{ &&&&//&do&nothing &&} }
可 见,Visit方法总共有四个不同的签名。在缺省实现中,各方法都转而调用public void Visit(Object f)方法,也就是什么都不作。当客户调用Visit方法时,会自动匹配类型。如果匹配不上的类型也会最终落到public void Visit(Object f)方法的怀抱中。在Visitor的子类中,只需实现关注的焦点就行了。例如某人只吃蔬菜不吃肉,那么他就没有必要再复写Visit(Meat m)方法了。这么做带来的另外一个好处就是,当添加新的食品时,即使不改变Visitor的代码,也不会产生任何编译或运行时的错误。如果修改,也只需修 改Visitor类并提供一个缺省实现。Visitor的子类如果并不关心新增加的类,便可不做任何改动。完整的代码如下:
{ &&public&virtual&void&Visit(Meat&m) &&{&this.Visit((object)m);&}
&&public&virtual&void&Visit(Vegetable&v) &&{&this.Visit((object)v);&}
&&public&virtual&void&Visit(Coffee&c) &&{&this.Visit((object)c);&}
&&public&void&Visit(Object&o) &&{ &&&&//&do&nothing &&} }
&ZhangSan&:&Visitor
{ &&public&override&void&Visit(Coffee&c) &&{ &&&&Console.Write(&&{0}:&Take&a&cup&of&{1},&&,this,&c); &&&&c.AddMilk(); &&&&c.AddSugar(); &&&&Console.WriteLine(); &&}
&&public&override&void&Visit(Vegetable&v) &&{ &&&&Console.WriteLine(&&{0}:&Take&some&{1}&,&this,&v&); &&} }
&LiSi&:&Visitor
{ &&public&override&void&Visit(Coffee&c) &&{ &&&&Console.Write(&&{0}:&Take&a&cup&of&{1},&&,this,&c); &&&&c.AddSugar(); &&&&Console.WriteLine(); &&}
&&public&override&void&Visit(Meat&v) &&{ &&&&Console.WriteLine(&&{0}:&Take&some&{1}&,&this,&v&); &&} }
{ &&public&abstract&void&Accept(&Visitor&visitor&); }
&Coffee:&Food&&
{ &&public&override&void&Accept(&Visitor&visitor&) &&{ &&&&visitor.Visit(this); &&}
&&public&void&AddSugar() &&{ &&&&Console.Write(&add&sugar.&&);&&& &&}
&&public&void&AddMilk() &&{ &&&&Console.Write(&add&milk.&&);& &&} }
&Meat:&Food&&
{ &&public&override&void&Accept(&Visitor&visitor&) &&{ &&&&visitor.Visit(this); &&} }
&Vegetable:&Food&&
{ &&public&override&void&Accept(&Visitor&visitor&) &&{ &&&&visitor.Visit(this); &&} }
&BuffetDinner
{ &&private&ArrayList&elements&=&new&ArrayList();
&&public&void&Attach(&Food&element&) &&{ &&&&elements.Add(&element&); &&}
&&public&void&Detach(&Food&element&) &&{ &&&&elements.Remove(&element&); &&}
&&public&void&Accept(&Visitor&visitor&) &&{ &&&&foreach(&Food&f&in&elements&) &&&&&&f.Accept(&visitor&); &&} }
{ &&public&static&void&Main(&string[]&args&) &&{ &&&&BuffetDinner&b&=&new&BuffetDinner(); &&&&b.Attach(new&Coffee()); &&&&b.Attach(new&Vegetable()); &&&&b.Attach(new&Meat());
&&&&ZhangSan&z&=&new&ZhangSan(); &&&&LiSi&l&=&new&LiSi();
&&&&b.Accept(&z&); &&&&Console.WriteLine(&----------------------&); &&&&b.Accept(&l&); &&} }
&条件外置&是我对封装变化的一个理解。现在才发现,原来设计模式中还有很多深奥的东西等待开发呢。
感谢关注 Ithao123精品文库频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊补仲山之衮,虽曲尽于巧心;和傅说之羹,实难调于众口。 是什么意思啊?_百度知道
补仲山之衮,虽曲尽于巧心;和傅说之羹,实难调于众口。 是什么意思啊?
我有更好的答案
大概就是东西都是用心做的,但众口难调。。
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁好一个“众口难调”_中国的社会治安最好吗_天涯博客
爱好写作,正直无私。
今日访问:[$DayVisitCount$]
总访问量:28621
开博时间:
博客排名:59282
(1)(1)(1)(4)(8)(1)(6)(8)(9)(1)(10)(5)(15)(13)(13)(23)(30)
  提到今年的春晚,可以说针砭多于褒扬。  一是《咬文嚼字》杂志挑错春晚:主持串词用错成语。1,小品《荆轲刺秦》将“秦王”错用成“秦公”黄宏一上台就说 :“想当初秦公金銮殿,图穷匕首见……”其中的“秦公”说错了,应说“秦王”才对。2,西施只比貂蝉老700岁,《爱的代驾》中闫学晶说:“我西施,她貂蝉,合着我比她老一千多年呢。”其实二人相差700年左右,离“一千多年”远着呢。3,《空山竹语》董卿说:“中国有句古话叫‘竹报平安’,虽然现代人早已不把报平安的家信写在竹简上了,但这青青翠竹在传统文化里一直被视为坚贞高洁、虚心向上的君子形象。”董卿显然把“竹报平安”理解成在竹简上写平安家信了,其实“竹报平安”指平安家信,也简称“竹报”,并不是在竹简上写平安信。4,字词语法错误:《创新小合唱》中相声演员周炜说:“今天你们四个跟我说相声,这不算新人吗?”字幕把表示疑问的语气助词“吗”误成了“嘛”。《今天的幸福》中多次出现“产前综合症”(字幕也如此)一语,规范的说法应是“产前综合征”。而《鼓韵龙腾》字幕解说词:“鼓是人类最早的音韵之一……”这是明显的主语谓语搭配不当。“鼓”是一种乐器,“音韵”即和谐的声音,二者不是同一个概念,只有鼓所发出的声音,才能称为“音韵”。所以正确的说法,应是“鼓乐是人类最早的音韵之一”。  二是有人提到龙年春晚不得不承认的五大硬伤:第一、“致敬三十年”,过早泄密找不到感觉。第二、少了赵本山,没有超越本山的小品。第三、到最后时刻,满台歌舞起不来节奏。第四、没有《难忘今宵》,《天下一家》挑不起大梁。第五、看完了春晚,除了舞美找不到震撼。  当然,包括哈文在内的“春腕”都在反复褒扬:这台春晚如何如何了不起。舞美设计好啊,没有广告啊,没有主持人念拜年贴啊,没有零点钟声啊,没有《难忘今宵》啊。有意思的是,晚会结束后,李咏居然还和哈文来了个长时间的热吻以示庆贺!  我注意了一下,凡是褒扬春晚的大都是春晚的组织者和参与者,凡是针砭春晚的大多是平民百姓!  于是,我此前就写过一篇批评春晚的文章《2012年春晚 最垃圾的春晚》,在论坛上获得很高的支持率,引发了人们的热烈讨论。今天又和一些人谈到春晚,人们说得最多的一句话是:众口难调!  我查了一下,众口难调来源于宋·欧阳修的《归田录》卷一:“补仲山之衮,虽曲尽于巧心;和傅说之羹,实难调于众口。”意思是,众人口味不同,很难调和得使大家都满意。亦比喻人多意见多, 很难协调统一,使人人都满意。  按照这些人使用这个成语的目的来看,当取“人多意见多, 很难协调统一,使人人都满意”一义。  果真如此,我就不得不啰嗦几句了。  首先,众口难调是一个多么奇妙的开脱语。我们春晚组才几个人啊,无论我们多么努力,节目无论编排的多精彩,你全国十几亿人,七嘴八舌的,说什么的都有,我能说得过你们吗?真是众口难调啊。言下之意,无论春晚多么糟糕,多么肤浅,多么和百姓不搭界,反正众口难调,你愿意说就说吧,反正听不听是我的事!  其次,使用众口难调能快速的将枪口对准观众。春晚搞得不好,诟病多,不是编导的责任,是观众的责任。我编导的春晚本来质量上乘,是观众缺乏欣赏水平,你们的胃口太大,你们的要求太高,你们的指责太离谱。你们自己看不惯不感兴趣,却横挑鼻子竖挑眼,怪得上我吗?要看你就看,不看就拉倒,别在这里说三道四的!  再次,众口难调标志着说话者的蛮横无理。不光是春晚的编导们用众口难调来为自己贴上蛮横无理的标签。许许多多明显存在错误的人和事,一旦听到不协调的声音,往往用众口难调来搪塞。不是检查自己,而是指责别人,或者干脆死猪不怕开水烫,死活不认帐。这样的事例举不胜举。  说到底,众口难调已经变味了。变成了某些人自我安慰的啊Q,变成了某些人死不认错的挡箭牌,变成了某些人吹牛拍马的道具,变成了某些人蛮横无理的打手,变成了某些人掩耳盗铃的手法。  我看许多看热闹的人,都弄错了春晚不受欢迎的本质,春晚好不好看,问题不在于形式,如舞美设计等,在于春晚的内容。如果春晚能贴近百姓生活,说百姓想说的话,讲百姓关注的事,哪怕是蜻蜓点水,也不会有这么多的争议。  我看,许多人,许多事,备受诟病,不是众口难调,而是法理、价值观、道德观的扭曲和倒置!  我看,还是恢复众口难调的本来面目为好!      分类: |

我要回帖

更多关于 章仲山 的文章

 

随机推荐