《大话设计模式》勘误

    尽管已经很仔细的检查和审核,但错误还是没有能避免。在此向已经购买了本书的读者诚意地说声抱歉。现勘误如下:

    1.01    P2 上方代码第二行,“if (O == "/") ”,应将"O"改为"B",本页第二段代码的倒数第五行,也是相同的错误,应将"O"改为"B"。

    1.02    P157 15.9节,第四段,"再添加引用System.configuratio15.",应将"15."改为"n".

    1.03    P61,第8行,原文:“你仔细观察一下,‘Pursuit(追求者)’和‘SchoolGirl(被追求者)’有没有相似的地方”?” 改为:“你仔细观察一下,‘Pursuit(追求者)’和‘Proxy(代理)’有没有相似的地方”?” 第9行,原文:“...三个方法,只不过‘SchoolGirl(被追求者)’送的礼物是‘Pursuit(追求者)’买的...” 改为:“...三个方法,只不过‘Proxy(代理)’送的礼物是‘Pursuit(追求者)’买的...” (trong  提供)

    1.04    P119,第4行,原文:“具体的小人,具体实现如何画出小人的头身手脚各个部分。” 改为:“具体的小人建造者,具体实现如何画出小人的头身手脚各个部分。” (trong  提供)

    1.05    P259 图 图中Colleague到Mediator之间的连线不应该多一个聚合关系而应该是关联关系。 (trong  提供)

    1.06    P271中间代码:原文:"UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();" 改为:"Flyweight uf = new UnsharedConcreteFlyweight(); "将更加准确。(trong  提供)

    1.07    P220 第1行 原文:“大鸟,棒着个手机,玩什么呢?"  其中“棒”改为:“捧” (cqchi 提供)

    1.08    P347 第5行 "简单理解就是耦断丝连" 更改为:"简单理解就是藕断丝连" (cqchi 提供)

    1.09    P84 9.5节 第1行 “你现在‘简历’对象里的数据都是string类型的,也就是值类型....”其中“也就是值类型”改为“而string是一种拥有值类型特点的特殊引用类型” (心界使者 提供)

    1.10    P10 在1.10前,增加文字如下“(作者注:以上代码读者如果阅读吃力,说明您对继承、多态、虚方法、方法重写等概念的理解不够,建议先阅读本书附录一,理解这些基本概念后再继续往下阅读。)

    1.11    P359 第4行“所以我们可以应用集合的RemoveRt方法...” 其中“RemoveRt”改为“RemoveAt”(心界使者 提供)

    1.12    P233 第2行:“哈,小菜说的和GoF说的不就是一会事吗!” 其中“一会事”改为“一回事”(心界使者 提供)

以上为二次重印时已修正的错误,以下为重印后发现的错误,特公告如下。

    2.01    P86 “客户端调用代码”下方代码第10行与第11行之间,即在“Resume c = (Resume)a.Clone();”与“c.SetWorkExperience("1998-2003", "ZZ企业");”之间加上一行代码:“c.SetPersonalInfo("男", "24"); ” (钢琴诗人 提供)

    2.02    P49 倒数第4行,"你的意思是,应该在内部组装完闭" ,其中“完闭”应该为"完毕" (cqchi 提供)

    2.03    P228 末尾代码,“class HandsetMP3 : HandSoft ”其中"HandSoft"应改为"HandsetSoft"(钢琴诗人 提供)

    2.04    P241 中间代码中的注释“ // 点菜完闭,通知厨房 ”其中“完闭”应该为"完毕"(钢琴诗人 提供)

    2.05    P62 本页三段代码第一句中 "GiveGift"由于是接口,所以都改为"IGiveGift" (cqchi 提供)

    2.06    P272  最下方代码开始处 在“//网站工厂”上面增加“using System.Collections; ”,以避免由于应用了Hashtable而使得初学者编译时不能通过。(钢琴诗人 提供)

    2.07    P285 中间代码第14行,即else语句里第3行“doubleplayValue”应注意当中有一个空格,即应该是“double playValue” 。 (钢琴诗人 提供)

    2.08    P286 中间文字“音符类(TerminalExpression)”,其中“音符类”应该为“音阶类”(钢琴诗人 提供)

    2.09    P295 中间,“结果显示”里的内容,“男人成功时”、“男人失败时”和“男人恋爱时”中“男人”改为“Man”,“女人成功时”、“女人失败时”和“女人恋爱时”中“女人”改为“Woman”

    2.10    P146 第7行与第8行之间,即“……此时如何办呢?”与“啊,我觉得那要增加好多类……”之间增加下方一段代码(钢琴诗人 提供)

 

class Department
{
    
private int _id;
    
public int ID
    
{
        
get return _id; }
        
set { _id = value; }
    }


    
private string _deptName;
    
public string DeptName
    
{
        
get return _deptName; }
        
set { _deptName = value; }
    }

}

    2.11    P340 倒数第三段中间部分,“set访问器没有显示设置参数”,其中“显示”应改为“显式”。(cqchi 提供)
    2.12    P352 中间四段代码,分别是Cat、Dog、Cattle、Sheep四个类中“public override string getShoutSound() ” ,其中“public”应改为"protected" (beach-boy 提供)

以上为三次重印时已修正的错误,以下为重印后发现的错误,特公告如下。

    3.01    p52 上方代码的第四个注释框中:“本类独有的方法,以区别于ConcreteDecoratorB”,其中“ConcreteDecoratorB”应改为“ConcreteDecoratorA”。(p大simba 提供)
    3.02    p164 最下边的注释框里:“设置ConcreteStateA的下一个状态是ConcreteB”,其中“ConcreteStateA”与“ConcreteStateB”应该把A和B互换过来”。(p大simba 提供)
    3.03    P332 倒数第三行 "我对你的敬仰真如涛涛江水",其中“涛涛江水”应改为“滔滔江水”。(zml 提供)
    3.04    P333 第十四行,“工厂工厂,公仔爱你,就像老鼠爱大米。” 其中“公仔”应改为“工仔”。(zml 提供)
    3.05    P37  4.4节下的第一段第五行, “招聘大学生的公司的咨讯",其中“咨讯”应改为“资讯”。(cqchi 提供) 
    3.06    前言中P15倒数第8行, "Erich Gamm",其中"Gamm"应该是"Gamma"(在P367,附录B的第一行有同样的错误). (Kappa 提供)

    3.07    P12与P68两页上面简单工厂模式的图,简单工厂类和运算类之间的关系应该是依赖(Dependency)而非关联(Association),即简单工厂类与运算类的连线是虚线箭头,而非实线箭头。(Steven Chen 和 hit_gsy 提供)

    3.08    p349 左上方那个说明框 “增加了override表示方法重写”指向上应该再向下一些,指向“override”才正确。

    3.09    P150 倒数第五行,“ProductB1是AccessUser”,其中“AccessUser”应改为“SqlserverDepartment”。( 欧尔 提供
    3.10    前言中P13 最后一行,“表示此名摘自”,其中“此名”应为“此句” (cqchi 提供)

    3.11    前言中p11倒数第六行“《Java与模式》(作者:阎宏”,其中在“阎宏”后应该加一个“)” (cqchi 提供)

    3.12    P11最后一行,“我们来看看这几个类的结构图。”与上文脱节。应该改为“好了,最后,我们来看看这几个类的结构图。”(cqchi 提供)

    3.13    P13第二段第二行,“接口还有另一种表示方法,俗称棒棒糖表示法,就是唐老鸭类实现了‘讲人话’的接口。”,其中“就是唐老鸭类实现了‘讲人话’的接口”改为“比如图中的唐老鸭类就是实现了‘讲人话’的接口”(cqchi 提供)

    3.14    p189 倒数第二行“你是意思是”应为“你的意思是”。(cqchi 提供)

    3.15    P313 倒数第三段“希望您能通过浏览器给她们投票,IE用户,请发送OO加选手编号到http://www.ootv.com/,Firefox用户请发送OO加选手编号到http://www.ootv.net/,其他浏览器用户请发送OO加选手编号到http://www.ootv.org/。”,其中将“通过浏览器”修改为“通过手机”,将“IE用户”修改为“移动用户”,将“Firefox用户”修改为“联通用户”,将“其它浏览器用户”修改为“其它手机用户”。这样的修改和后面的很多地方就都不会有矛盾之处了。(cqchi 提供)

    3.16    p313 倒数第四行,“进级决赛”改为“晋级决赛”。(cqchi 提供)

    3.17    p103 第六段,“买一只好的股票放在那里所谓的‘悟股’”,其中“悟股”应为“捂股” (cqchi 提供)

    3.18    P360 第四段,第四行,“HelloWorld是字符型”,其中“字符型”应为“字符串型”(cqchi 提供)

    3.19    P360 第四段,第五行,“还有就是ArrayList对于存放值类型的数据,比如int型、string型或者结构struct的数据”,其中在"string型"和“或者结构”之间增加“(string是一种拥有值类型特点的特殊引用类型)”说明。(cqchi 提供)

    3.20    P132,倒数第2行 “将有关状态存入具体现察对象” 其中“现”字应为“观”字。(薄雾轻寒 提供)

    3.21    P147   最后一行的“定义一个创建访问User表对象的抽象的工厂接口”,其中“User”应该是“Department”(langya918 提供)

    3.22    P148   第2个提示框中的"SplserverDepartment工厂",其中“Splserver”应该是“Sqlserver"(langya918 提供)

    3.23    P148   第3个提示框中的"OleDBDepartment" 应该是"AccessDepartment" (langya918 提供)

    3.24    P317   中间UML图的标题中,“12号选手 代理(ptoxy)”,其中“ptoxy”应改为“proxy”

    以上为六次重印时已修正的错误。

    4.01    P75  中代码

//工厂方法模式
   IFactory factory = new UndergraduteFactory();  //要改变为社区志愿者,只需改变此处
   LeiFeng student = factory.CreateLeiFeng();
   student.BuyRice();
   student.Sweep();
   student.Wash();

修改为

//工厂方法模式
   IFactory factory = new UndergraduteFactory();  //要改变为社区志愿者,只需改变此处
    LeiFeng studentA = factory.CreateLeiFeng();
   studentA.BuyRice();
    LeiFeng studentB 
= factory.CreateLeiFeng();
   studentB.Sweep();
    LeiFeng studentC 
= factory.CreateLeiFeng();
   studentC.Wash();

     修改原因是因为这工厂方法模式的实现代码要和简单工厂模式的代码做对比,有读者提出,原有的写法让人不是很容易理解,本人仔细分析觉得读者讲得有道理,在此修改完善。

     4.02 P35 第四行最后,“The Open-Closeed”中 "Closeed"应改为“Closed” (顾行星 提供)

     4.03 P16 代码第二行 public Metabolism (Oxygen oxygen,Water water),当中少了一个void,应该是public void Metabolism (Oxygen oxygen,Water water)  (Shikiro 提供

     4.04 P186 代码第一行 “class 游戏角色” ,当中“游戏角色”应该改为“GameRole”(秦萌 提供

     4.05 P288 下方代码第二行 “context.演奏文本” ,当中“演奏文本”应该改为“PlayText”(秦萌 提供


     若读者您还发现什么错误,请在此回复或给我留言,我将及时公布。在此先说一声谢谢。

posted on 2007-12-13 19:48 伍迷 阅读(5015) 评论(166) 编辑 收藏

评论

#67楼  回复 引用   

楼主,我给你建议:
1、你的Bug勘误表不应该有重复的Bug Serial No.。你不妨自顶而下如
1.01 bug1
...
1.10 bug10
2.01 bug11
...
2.02 bug12
2、回到我之前的问题,我是不是可以这么理解:你撰写的《大话》第二版,连代码里的字串都改中文成英文了。
为什么?我倒是觉得没有必要。一个中文字串,我本来觉得很好,可你把“男人”变成“Man”之后,陡增了我的误解,这不,我拿着你的第一版来这里对照勘误,各说各话
这是你的责任,至少,你没有把第二版的背景交代清楚,譬如“男人”变“Man”之类
3、再提一个勘误的bug,如下
P146 第7行与第8行之间,即“……此时如何办呢?”与“啊,我觉得那要增加好多类……”之间增加下方一段代码(钢琴诗人 提供) ...
我觉得这里增加的代码真是鸡肋。你回头想想为什么会让读者有这个感觉吧。我希望,这种似是而非的勘误不会出现在你的第三版上
2008-04-07 19:15 | 贺新亚[未注册用户]

#68楼  回复 引用   

我得说清楚,我看好这本书,也推荐朋友买来读,毕竟,现实上很多一知半解的人翻译糟蹋了很多外文书籍,让本来就颇具理论性的书看起来有如天文。他们都懒得自己组织文字撰写了,又或者没有这个能力。你的书具有通俗易懂的优点。
国内人原创写的计算机图书,我少见过好的。我能看出他有些许水平,但是章回段落的组织能力实在差劲,很多地方明显是凑字数乱抄,自己没有想清楚就敢晾出来,亏待了认真两字,真是让人陡增无名之火
说你吊儿郎当确实不恰当,但是,我认真的跟你说,我从google搜索“大话设计模式 勘误”到了这里,看到的确实不是一个很认真的勘误网页。
2008-04-07 19:38 | 贺新亚[未注册用户]

#69楼[楼主]  回复 引用 查看   

@贺新亚
感谢您给我的第一条建议,我已经更正了勘误的编号,这的确是一个好主意.

第二个问题,您的理解其实不对,把代码中的中文改成英文,是在图书正式出版之前就完成的,当时和编辑还商量过,哪一种方式更合理,尽管中文代码容易阅读,但却非常不规范(现实中一般不用中文写代码).因此最终12月份出版时,我已经是将所有的代码都改成英文的.(您可查看编辑写的序,当中有提到)

至于您提到的将"男人"改成"man",仅仅只是一个字符串的变化.是因为那段代码执行后不会出现"男人成功时”、“男人失败时”和“男人恋爱时”的字样,而只会出现"man成功时”、“man失败时”和“man恋爱时”因此这算是第一二次印刷时的小bug(一直存在的bug),在勘误中声明,并在第三次印刷时更正.您可以按照代码输入执行后就知.

至于第三个问题,您可查看本文第30楼
#30楼 218.11.51.*
@伍迷
P146页 对于Department类,由于没有编排上,建议加一句提示(此类同User类类似),便于手头上没有下载源代码的读者轻松阅读。

增加它的目的是为了给没有下载源代码的读者轻松阅读.而只写"此类同User类类似"并不严谨,它们之间有属性不相同的地方,初学者很难从书中完全将代码复原,因此增加这段代码很有必要。

希望我的这些解释可以令您满意。也感谢您的指正。
2008-04-08 09:48 | 伍迷      

#70楼  回复 引用   

书中对于里侍代换代换原则(/P41)的讲解中所举的鸟例子,是不恰当的,或者说是偷换概念的讲解。
生搬硬设的例举不会有任何说服力,而且一定会产生不好的影响和效果!!
我们都知道“企鹅是一种鸟”,这不止是在生物科学上的周知常识!
不错,“企鹅不是一种“能飞的鸟””,可这个需要作者曲径通幽的告诉我们吗?
事实上的结果是:书中的这种文字描述和例举,对于本来就有概念的人而言,心领神会似是而非;对于那些本来就没有概念的“新人”而言,毫无意义,更陡增困惑!
2008-04-10 10:26 | 贺新亚[未注册用户]

#71楼[楼主]  回复 引用 查看   

@贺新亚
对于你的这种评价,尽管仁者见仁,智者见智,我想还是有必要解释一下。我承认,书中由于大量的生活实例,可能会有小部分例子并不是很准确。但这是建立在不影响读者对技术的理解为前提之下的。另外,除了数学意义的表述,绝大部分对技术的解释,特别所做的类比都会存在一定的偏差。而数学意义的表述准确有之,理解非常困难。类比可能不准确,却反而能起到加深理解的目的,因此我不认为这是什么根本的问题。

本书风格就是用大量生活实例来讲解技术难点。企鹅是一种鸟,因此企鹅类可以继承鸟类,而飞翔并不是所有的鸟都必需的能力,比如企鹅或鸵鸟就不行,这样很形象的表述就是本书的风格,这些常识也不会给读者产生什么歧义。甚至说,我是很刻意的要让文字里充满了大家都知道的常识,目的是让人感觉很容易理解。

您如果不喜欢,只能说,本书没有让您满意,我很抱歉。也或许,您更喜欢非常正规的讲解技术,我建议您直接阅读GoF《设计模式》,里面应该没有任何歧义,可能会让您满意。
2008-04-10 11:05 | 伍迷      

#72楼  回复 引用   

"企鹅是一种鸟,因此企鹅类可以继承鸟类,而飞翔并不是所有的鸟都必需的能力,比如企鹅或鸵鸟就不行",这是对的。
可p41里所举的例子,真的不恰当。有恰当的例子,而且可以写的一样甚至更生动。
2008-04-10 11:44 | 贺新亚[未注册用户]

#73楼  回复 引用   

吹毛求龇,我的言辞显得如此
不好意思,我学数学的,对概念力求精确,不存歧义
很多的科学发现都是从对基础概念的怀疑而得到的,譬如爱恩斯坦对时间和距离的思考:)
扯远了,实话说,我不是一个聪明的人,常受一些似是而非的理论而困惑;我现在读书看字几近咬文嚼字,有意识的,从泥潭里爬出来看那些在泥潭里挣扎的人,愤愤不平
对于某个理论,光看一本书是不大可能有很好的理解的,就算这本书的论述有多严谨。所谓兼听则明,何况,每个人的知识背景千差万别。
现在我们终于知道做老师的高度和责任
2008-04-10 12:56 | 贺新亚[未注册用户]

#74楼  回复 引用   

GoF的《设计模式》我看过的,我是对照中英文一起看;书是很严谨,可翻译还真的一如既往不求甚解。那些应该加粗整体看待的概念,中文表达得朝三暮四,让人不知所措
2008-04-10 13:05 | 贺新亚[未注册用户]

#75楼[楼主]  回复 引用 查看   

@贺新亚
在本书41页,大鸟提了一个问题,他说,“如果鸟是可以飞的,企鹅不会飞,那是企鹅是鸟吗?企鹅可以继承鸟这个类吗?”这里面,大鸟其实是在挖了一个坑,故意让小菜去跳的,常识都知道企鹅是鸟,所以小菜就说:“企鹅类可以继承鸟类”。

而大鸟后面就说到“尽管在生物学分类上,企鹅是一种鸟,但在编程世界里,企鹅不能以父类——鸟的身份出现,因为前提说,所有鸟都能飞,而企鹅飞不了,所以企鹅不能继承鸟类。”

首先这本书在这里是以一种对话形式讲解的,在日常对话中,说个常识问题故意让人上当的情形其实很多。我之所以这样写,其实也是想加深读者对里氏代换原则的理解,也就是要满足这个原则是有前提的,即:“一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,…………”

你的回复后,我认真再看了书中的这段文字,我认为这个例子在这里是很合适的。因此对你的看法我有保留意见,但没有令你满意,我很抱歉。
2008-04-10 20:06 | 伍迷      

#76楼  回复 引用   

p164最下边的注释框里的:“设置ConcreteStateA的下一个状态是ConcreteB”应该把A和B互换过来。
2008-04-28 09:46 | p大simba[未注册用户]

#77楼  回复 引用   

诚然,出一本完美无缺的书是很难的。作者能做到这样已经很可贵了。
2008-04-28 09:53 | p大simba[未注册用户]

#78楼  回复 引用   

第一版P332倒数第三行 应为:滔滔江水
P333 公仔爱你,就像老鼠爱大米,公仔应改为工仔
2008-05-05 19:21 | zml[未注册用户]

#79楼[楼主]  回复 引用 查看   

@p大simba
@zml
感谢两位的发现,很低级的错误,谢谢指正。
2008-05-05 20:59 | 伍迷      

#80楼  回复 引用   

P37 “招聘大学生的公司的咨讯",应为"资讯"
2008-05-09 13:34 | cqchi[未注册用户]

#81楼[楼主]  回复 引用 查看   

@cqchi
感谢您的指正,我还专门去查证了这两个词的区别,的确,资讯的意思是资料讯息的意思,而没有咨讯这个词,只有咨询,那是征求意见 (多指行政当局向顾问之类的人员或特设的机关征求意见)。如心理咨询、业务咨询等。
2008-05-11 10:05 | 伍迷      

#82楼  回复 引用 查看   

今天到货,看了再说:)
2008-05-15 10:07 | 泛舟      

#83楼  回复 引用   

P15倒数第8行, Erich Gamm应该是Gamma.
2008-06-04 12:55 | Kappa[未注册用户]

#84楼  回复 引用 查看   

--引用--------------------------------------------------
p大simba: p52的第四个注释框中:本类独有的方法,以区别于ConcreteDecoratorB,应该是ConcreteDecoratorA
--------------------------------------------------------
这里为什么是ConcreteDecoratorA呢

--引用--------------------------------------------------
Kappa: P15倒数第8行, Erich Gamm应该是Gamma.
--------------------------------------------------------
P15没有你说的这个错误啊。
我的是第三次印刷的
2008-06-23 16:19 | RainSky      

#85楼[楼主]  回复 引用 查看   

@RainSky
Kappa: P15倒数第8行, Erich Gamm应该是Gamma.

指的是前言中的第15页
2008-06-23 17:08 | 伍迷      

#86楼  回复 引用 查看   

p349
左上方那个说明框 增加了override表示方法重写,是不是应该向下一点,知道override上边呢。
2008-06-24 10:37 | AgpSky      

#87楼  回复 引用 查看   

伍迷老师。在装饰模式里面,第三版的时候能不能解释一下为什么会使用的base,和使用base以后的作用呢。
我例如断点看出来执行过程了。但是还理解不透彻,希望指点一下。
也许我对base理解的不好吧。见谅。
2008-06-27 16:55 | AgpSky      

#88楼[楼主]  回复 引用 查看   

@AgpSky
左上方那个说明框 “增加了override表示方法重写”,应该向下一点。感谢指正。


这其实是装饰模式的关键所在。你不妨自己输入一遍代码,然后再思考。如果一遍不行,那就两遍,最好达到可以默写的地步。每一次的编写代码,你都会更进一步思考它的。相信用不了几次,你就能完全理解它的精髓的。

我并不是不可以向你解释,但是设计模式的确是思维的体操,自己的钻研思考要远远比我告诉你结果好得多。希望你能理解我的意思。
2008-06-29 22:39 | 伍迷      

#89楼  回复 引用 查看   

关于抽象工厂模式这一章
P150:
图下面第一段文字最后一句话:“比如ProductA1可以理解是SqlserverUser,而ProductB1是AccessUser”;
这里为什么ProductB1是AccessUser呢?如果没有理解错的话此处ProductB1应该是实现IDepartment接口,所以是不是应该是SqlserverDepartment!还是我理解有问题!
2008-06-30 13:13 | 欧尔      

#90楼  回复 引用   

2.03和2.06是一样的
2008-07-21 11:34 | BJL[未注册用户]

#91楼[楼主]  回复 引用 查看   

@BJL
谢谢指正,这实在是是勘误里的错误呀.
2008-07-21 12:55 | 伍迷      

#92楼  回复 引用   

对于“3.07”,在P68的图应该做相应的更改,因为它们是同一个图.
但前提是“3.07”所陈述的内容是正确的
它正确吗?我也不知道,所以请顺带解释一下
2008-07-23 17:01 | hit_gsy[未注册用户]

#93楼[楼主]  回复 引用 查看   

@欧尔
您说得没错,这里是有点问题,应该是"ProductB1是SqlserverDepartment".感谢您的指正。


@hit_gsy
P68的确是同样图的错误。
我简单解释一下,简单工厂类并没有运算类的字段,而仅仅是createOperation这个方法返回一个Operation的对象,一般来说,关联关系在C#中作为类的字段来表示,而依赖关系则是函数的参数或者是返回值来表示。所以此处应该是依赖而不是关联。
2008-07-23 21:49 | 伍迷      

#94楼  回复 引用   

再来挑几个错字:
前言
P9 最后一行“表示此名摘自”应为“表示此句摘自”
p11倒数第六行“《Java与模式》(作者:阎宏”应为“《Java与模式》(作者:阎宏)”
正文
p11 引入UML类图的对话太过牵强
“如果要修改界面呢?”
“那就去修改界面呀,关运算什么事呀。”
后面就是UML图的介绍,读者就不明白这两句话到底有什么用!
P13“接口还有另一种表示方法,俗称棒棒糖表示法,就是唐老鸭类实现了“讲人话”的接口”
这句更是突兀,因为前面从没提到唐老鸭类。
p189 倒数第二行“你是意思是”应为“你的意思是”
或许吹毛求疵了点,但我觉得一本书应该严谨,虽然以大话方式来写!


2008-07-29 17:00 | cqchi[未注册用户]

#95楼  回复 引用   

还有话要说,不吐不快。
最后一章以超级模式大赛的形式来总结各个模式的差别,感觉很新颖。但是前后有些矛盾。
P313写明“希望您能通过浏览器投票”
P330又写明“我们的短信平台刚刚关闭”。

2008-07-29 17:36 | cqchi[未注册用户]

#96楼[楼主]  回复 引用 查看   

@cqchi
非常感谢您的指正,没想到还能找到如此多的错误,虽然大都不影响阅读,但是错误毕竟是错误,还是应该改正的。谢谢支持!等下次印刷(估计是第五次印刷)出来,我将赠送您一本,以对本书指出如此多的错误的感谢!请您记着把联系方法发Mail给我。
2008-07-29 22:20 | 伍迷      

#97楼  回复 引用   

:-)请记得签名!感谢!
2008-07-30 09:21 | cqchi[未注册用户]

#98楼  回复 引用   

p313 “进级决赛”应为“晋级决赛”
2008-07-30 09:36 | cqchi[未注册用户]

#99楼  回复 引用 查看   

P22
2.4策略模式上面那段:
就是大鸟接着说:""。这里大鸟的意思是小菜需要想一个办法可以解决面对算法的时常变动,应该有更好的办法。但是在后面讲过策略模式以后,并没有解决这个问题。因为策略模式和简单工厂结合以后当算法变动的时候还是需要编译的。所以这里的写法上是不是有些问题。虽然在最后讲到了应用反射,但是开始给读者的感觉就是下面出场的模式就是解决这个问题的,却没有解决了。而p28 2.7上面的小结那里给读者的感觉就是应用策略模式以后耦合度降低了。
请伍迷老师讲解一下。谢谢
不知道是我的理解问题,还是疏忽了。
2008-07-30 16:38 | AGPSky      

#100楼[楼主]  回复 引用 查看   

@AGPSky
建议你去阅读“抽象工厂模式”中的讲解反射的一段,应该就可以明白如何将耦合度进一步降低了。
2008-08-01 09:18 | 伍迷      

#101楼  回复 引用 查看   

--引用--------------------------------------------------
伍迷: @AGPSky
建议你去阅读“抽象工厂模式”中的讲解反射的一段,应该就可以明白如何将耦合度进一步降低了。
--------------------------------------------------------
那里我看了,我的意思是:在引入策略模式前面的讲解让读者以为策略模式就可以完全解决问题了(这里引入的时候是不是有点问题)。其实并没有,还需要应用到反射。
2008-08-01 13:19 | AGPSky      

#102楼  回复 引用 查看   

正在看这本书,写的真的很好。很适合入门,看一个模式再对应看WEBCAST一讲。书写的真不错。
-----------------------------
P56页最后一个字是“强”还是“弓虽”?~~
-----------------------------
2008-08-10 08:15 | Astar      

#103楼  回复 引用   

p103 “买一只好的股票放在那里所谓的‘悟股’”应为“捂股”
2008-08-12 10:20 | cqchi[未注册用户]

#104楼[楼主]  回复 引用 查看   

@AGPSky
你讲的有些道理,不过这并不是错误,而是缺陷(它并不太影响阅读),要改就得大动作,本次版本就不做改动了。感谢您的提醒。

@Astar
P56页最后一个字是“弓虽”。是故意这样的。

@cqchi
p103 “的确应该是“捂股”,谢谢。
2008-08-13 20:38 | 伍迷      

#105楼  回复 引用   

再来两个
P360 “HelloWorld是字符型”应为“字符串型”
“还有就是ArrayList对于存放值类型的数据,比如int型、string型”,string实际上不是值类型。
p362 "委托是对函数的封装,可以当作给方法的特征指定一个名称。而事件则是委托的一种特殊形式,当发生有意义的事情时,事件对象处理通知过程。"
应为“事件对象通知处理过程”。
2008-08-28 09:38 | cqchi[未注册用户]

#106楼  回复 引用   

P260,
if(colleague==colleague1)
{
colleague2.Notify(message);//colleague1.Notify(message);??
}
else
{
colleague1.Notify(message);??colleague2.Notify(message)??

}
2008-08-30 09:56 | AstarNoLogin[未注册用户]

#107楼[楼主]  回复 引用 查看   

@cqchi
P360 “HelloWorld是字符型”应为“字符串型”
“还有就是ArrayList对于存放值类型的数据,比如int型、string型”,string实际上不是值类型。

的确是问题,已经修正

p362 "委托是对函数的封装,可以当作给方法的特征指定一个名称。而事件则是委托的一种特殊形式,当发生有意义的事情时,事件对象处理通知过程。"

这一句没有问题,就应该是"事件对象处理通知过程"
2008-09-18 20:58 | 伍迷      

#108楼[楼主]  回复 引用 查看   

@AstarNoLogin
这一段代码没有问题,就应该是这样的。
2008-09-18 20:59 | 伍迷      

#109楼  回复 引用   

p25的代码结构图中,CashContex和CashSuper之间是聚合关系,而代码实现上是关联关系,是我理解错误?
2008-09-28 18:30 | eeee[未注册用户]

#110楼  回复 引用   

非常棒的书!发现错字。第4次印刷版,第132页,倒数第6行 “将有关状态存入具体现察对象” 其中“现”字应为“观”字!
2008-12-24 08:56 | 薄雾轻寒[未注册用户]

#111楼[楼主]  回复 引用 查看   

@薄雾轻寒
没想到,这么久了,你还能查到错误字,非常感谢!
2008-12-24 21:19 | 伍迷      

#112楼  回复 引用   

P3页修改后的计算器的代码,对string类型使用switch应该是错误的
2009-01-06 12:15 | 郭帆[未注册用户]

#113楼[楼主]  回复 引用 查看   

@郭帆
不知你是否是用C#,我这里用的C#对string使用switch是可以的.
2009-01-06 16:19 | 伍迷      

#114楼  回复 引用   

伍迷:
你寄来的书已收到,感谢!!让我们一起为写出优秀的代码努力!!!
2009-01-08 10:52 | cqchi[未注册用户]

#115楼  回复 引用 查看   

第18章186页的备忘录模式这里,提到了命令模式,而命令模式是在后面才有的,为了书的连贯性,建议调整一下章节的顺序。
2009-07-11 23:28 | 廖勇军      

#116楼  回复 引用 查看   

时间过得有点久了,好多地方都忘记了,挑主要的说吧:
1.原型模式不是clone,整个原型模式一章似乎都跟原型模式没有任何关联,一直在讲clone?

原型模式重点是在解决对象创建问题,复制只是手段。GoF的意图一节:用原型实例指定创建对象的种类,并通过拷贝这些原型对象创建新的对象。

原型本质上解决的是跟工厂一样的问题,所以依赖倒置是必要的条件,而这一章的所有例子中,Resume都一直以具体类作为变量类型。整章不论例子、实现还是讲解都只是在强调复制的问题。


2.工厂方法模式,根据GoF的类图,工厂方法与其调用者属于同一类中(即工厂方法没有自己的单独的类,所以这个模式叫工厂方法。),而大话中的讲述与此对应不上(我怎么看都像抽象工厂......)


留个MSN吧 欢迎探讨 csf178@163.c。m
2009-11-11 16:40 | winter-cn      

#117楼[楼主]  回复 引用 查看   

@winter-cn
感谢你的回复。

1)关于原型模式。我专门去查了GOF的原书。应该说我的写作没有偏离主题,不是错误。至于每个人对原型的自己理解,可能有所偏差,我想也是很正常的。


<br />
GOF书中摘抄:
1意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
3适用性最后一条:当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
4结构:图中Prototype类的方法是Clone(),它是声明一个克隆自身的接口.ConcretePrototype类,实现一个克隆自身的操作。<br />


大话书中摘抄

(1)原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。

(2)但对于.NET而言,那个原型抽象类Prototype是用不着的,因为克隆实在是太常用到了,所以.NET在System命名空间中提供了ICloneable接口,其中就是唯一的一个方法Clone(),这样你就只需要实现这个接口就可以完成原型模式了。

(3)不用重新初始化对象,而是动态的获得对象运行时的状态。



<br />

也许你的意思我还是不明白,希望您能再阅读原书与大话后帮我说明,我书中的错误在哪里。
2009-11-12 09:30 | 伍迷      

#118楼[楼主]  回复 引用 查看   

2)关于工厂方法。您提到“工厂方法没有自己的单独的类”,这样的表述是有问题的。

原书中说工厂方法的意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。(这里提到了接口,提到了子类)

后来在3动机里举的例子,Application类和MyApplication类中都有CreateDocument。书中说“我们称CreateDocument是一个工厂方法。因为它负责‘生产’一个对象”



2009-11-12 09:40 | 伍迷      

#119楼  回复 引用 查看   

引用伍迷:
2)关于工厂方法。您提到“工厂方法没有自己的单独的类”,这样的表述是有问题的。

原书中说工厂方法的意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。(这里提到了接口,提到了子类)

后来在3动机里举的例子,Application类和MyApplication类中都有CreateDocument。书中说“我们称CreateDocument是一个工厂方法。因为它负责‘生产’一个对象”

"工厂方法没有自己的单独的类",这个只是针对表面现象的一种描述

请你注意GoF的UML类图中有个AnOperation
product=FactoryMethod()是位于这个方法当中的
而你在大话中 使用方法则是
IFactory operFactory=new AddFactory;
Operation oper=operFactory.CreateOperation();

我不是主张完全照搬书上的东西 但请体会其背后的区别:调用一个自己的方法来创建对象与创建一个工厂对象再调用其方法来创建对象,你认为哪一个才是工厂方法呢?
2009-11-12 10:30 | winter-cn      

#120楼[楼主]  回复 引用 查看   

@winter-cn
我明白你对工厂方法理解上的意思了。你说得没错,GOF的UML的确是这样写的,不过GOF的书是95年写的,后人对这些模式都有了各自的研究,我看过的设计模式的书不下10本。加上一些国内外对设计模式的研究。所以我写的已经不完全是GOF的工厂方法,而是更加合理和易懂的应用。

也许你觉得我不够权威。
推荐你阅读
http://www.dofactory.com/Patterns/PatternFactory.aspx
这篇文章以及《Java与模式》这本书,里面有很详细的说明。
2009-11-12 10:48 | 伍迷      

#121楼[楼主]  回复 引用 查看   

@winter-cn
不过对于工厂方法模式,我的写作中的确有一点小遗憾。是一位读者指出来的,我已经在本博文的最后提到。
4.01 P75 中代码

//工厂方法模式
IFactory factory = new UndergraduteFactory(); //要改变为社区志愿者,只需改变此处
LeiFeng student = factory.CreateLeiFeng();
student.BuyRice();
student.Sweep();
student.Wash();

修改为

//工厂方法模式
IFactory factory = new UndergraduteFactory(); //要改变为社区志愿者,只需改变此处
LeiFeng studentA = factory.CreateLeiFeng();
studentA.BuyRice();
LeiFeng studentB = factory.CreateLeiFeng();
studentB.Sweep();
LeiFeng studentC = factory.CreateLeiFeng();
studentC.Wash();
修改原因是因为这工厂方法模式的实现代码要和简单工厂模式的代码做对比,有读者提出,原有的写法让人不是很容易理解,本人仔细分析觉得读者讲得有道理,在此修改完善。



2009-11-12 10:50 | 伍迷      

#122楼[楼主]  回复 引用 查看   

@winter-cn
本着对读者负责任的态度,如果真的是书中的错误和缺陷,我都会认真研究,并在下一次印刷时提交出版社修正。所以还是感谢你的回复,也许我书中的确还有错误,确认后我一定会更正的。
2009-11-12 10:53 | 伍迷      

#123楼  回复 引用 查看   

引用伍迷:
@winter-cn
感谢你的回复。

1)关于原型模式。我专门去查了GOF的原书。应该说我的写作没有偏离主题,不是错误。至于每个人对原型的自己理解,可能有所偏差,我想也是很正常的。

...

关于方向性的东西的确比较难以表达 又看了一遍大话和GoF的相应章节

这样说吧,按照GoF的本意Clone()意在复制类型,而非复制数据,而大话中的例子和讲解,基本都是在强调复制数据。
大话中的所有例子 盛放Resume的变量都在使用具体类型Resume 用原型实例指定创建对象的种类就无从谈起了

适用性最后一条算是特例,但是貌似大话中的场景也不符合这一条(Resume显然不是状态有限的类)
2009-11-12 10:56 | winter-cn      

#124楼[楼主]  回复 引用 查看   

@winter-cn
如果只是复制数据,那我章节后面的浅复制和深复制就没必要再讲解了。

‘浅复制’被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其它对象的引用都仍然指向原来的对象。但我们可能更需要这样的一种需求,把要复制的对象所引用的对象都复制一遍。比如刚才的例子,我们希望是a、b、c三个引用的对象都是不同的,复制时就一变二,二变三,此时,我们就叫这种方式为‘深复制’,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。”
2009-11-12 11:03 | 伍迷      

#125楼  回复 引用 查看   

引用伍迷:
@winter-cn
我明白你对工厂方法理解上的意思了。你说得没错,GOF的UML的确是这样写的,不过GOF的书是95年写的,后人对这些模式都有了各自的研究,我看过的设计模式的书不下10本。加上一些国内外对设计模式的研究。所以我写的已经不完全是GOF的工厂方法,而是更加合理和易懂的应用。

也许你觉得我不够权威。
推荐你阅读
http://www.dofactory.com/Patterns/PatternFactory.aspx这篇文章以及《Java与模式》这本书,里面有很详细的说明。

这个并非权威性的问题 我之所以提出来 不仅是因为跟GoF不符 也是因为我自己不能认同这个观点

从工厂方法要解决的问题和应用场景来看 你的修改不能够解决 而且你修改之后的代码与抽象工厂是重复的

看看下面的动机部分:
引用
框架使用抽象类定义和维护对象之间的关系。这些对象的创建通常也由框架负责。
考虑这样一个应用框架,它可以向用户显示多个文档。在这个框架中,两个主要的抽象是类Application和Document。这两个类都是抽象的,客户必须通过它们的子类来做与具体应用相关的实现。例如,为创建一个绘图应用,我们定义类DrawingApplication和DrawingDocument。Application类负责管理Document并根据需要创建它们—例如,当用户从菜单中选择Open或New的时候。因为被实例化的特定Document子类是与特定应用相关的,所以Application类不可能预测到哪个Document子类将被实例化—Application类仅知道一个新的文档何时应被创建,而不知道哪一种Document将被创建。这就产生了一个尴尬的局面:框架必须实例化类,但是它只知道不能被实例化的抽象类。
FactoryMethod模式提供了一个解决办案。它封装了哪一个Document子类将被创建的信息并将这些信息从该框架中分离出来。
Application的子类重定义Application的抽象操作CreateDocument以返回适当的Document子类对象。一旦一个Application子类实例化以后,它就可以实例化与应用相关的文档,而无需知道这些文档的类。我们称CreateDocument是一个工厂方法(factorymethod),因为它负责“生产”一个对象。
2009-11-12 11:14 | winter-cn      

#126楼  回复 引用 查看   

引用伍迷:
@winter-cn
如果只是复制数据,那我章节后面的浅复制和深复制就没必要再讲解了。

‘浅复制’被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其它对象的引用都仍然指向原来的对象。但我们可能更需要这样的一种需求,把要复制的对象所引用的对象都复制一遍。比如刚才的例子,我们希望是a、b、c三个引用的对象都是不同的,复制时就一变二,二变三,此时,我们就叫这种方式为‘深复制’,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。”

我这里所说的数据也包括子对象 深复制和浅复制是Clone实现问题 我说的是使用问题


我指原型主要希望解决的是这样的问题:
void ProcessNode(INode node, Object data)
{
INode newnode=node.Clone();
newnode.Data=data;
node.append(newnode);
}

INode是一个接口 如果INode被改为一个具体类 那就没有意义了
prototype的意图就是由node指定newnode的类型,如果newnode的类型已经确定为一个具体类型,那node又如何指定它类型呢?

同样的道理,Resume的例子中Resume是一个具体类型,从一个Resume克隆到另一个Resume,这就只是简单的clone而已
2009-11-12 11:28 | winter-cn      

#127楼[楼主]  回复 引用 查看   

@winter-cn
这样吧,你根据http://www.dofactory.com/Patterns/PatternFactory.aspx
上的样例代码,写一个C#的你认为是工厂方法的例子,这样可能我就好理解一些了。我想代码才是最好沟通的方式。
我的邮箱是chengjielong@163.c。m

另外你提到“而且你修改之后的代码与抽象工厂是重复的”,我在抽象工厂一章有对这两种模式做了讲解。可阅读后再议。
2009-11-12 11:30 | 伍迷      

#128楼  回复 引用 查看   

引用伍迷:
@winter-cn
本着对读者负责任的态度,如果真的是书中的错误和缺陷,我都会认真研究,并在下一次印刷时提交出版社修正。所以还是感谢你的回复,也许我书中的确还有错误,确认后我一定会更正的。


伍迷前辈的确负责任 本来我也只是捎带一提 没想到作者竟这么认真 对这种网上的既无来源 又无人负责的言论其实大部分都是无人理会的 佩服楼主的认真精神
2009-11-12 11:33 | winter-cn      

#129楼  回复 引用 查看   

引用伍迷:
@winter-cn
这样吧,你根据http://www.dofactory.com/Patterns/PatternFactory.aspx
上的样例代码,写一个C#的你认为是工厂方法的例子,这样可能我就好理解一些了。我想代码才是最好沟通的方式。
我的邮箱是chengjielong@163.c。m

另外你提到“而且你修改之后的代码与抽象工厂是重复的”,我在抽象工厂一章有对这两种模式做了讲解。可阅读后再议。

邮箱地址处理一下 要不然会很多垃圾邮件的 :P
这个是我改的代码:
// Factory Method pattern -- Structural example  
using System;

namespace DoFactory.GangOfFour.Factory.Structural
{
    class MainApp
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>

        static void Main()
        {

            // An array of creators
            Creator[] creators = new Creator[2];

            creators[0] = new ConcreteCreatorA();
            creators[1] = new ConcreteCreatorB();

            // Iterate over creators and create products

            foreach (Creator creator in creators)
            {
                creator.AnOperation();
            }

            // Wait for user
            Console.ReadKey();
        }
    }
    /// <summary>
    /// The 'Product' abstract class
    /// </summary>

    abstract class Product
    {

    }
    /// <summary>
    /// A 'ConcreteProduct' class
    /// </summary>

    class ConcreteProductA : Product
    {

    }
    /// <summary>
    /// A 'ConcreteProduct' class
    /// </summary>
    class ConcreteProductB : Product
    {

    }
    /// <summary>
    /// The 'Creator' abstract class
    /// </summary>

    abstract class Creator
    {
        public abstract Product FactoryMethod();
        public void AnOperation()
        {
            Product product = FactoryMethod();
            Console.WriteLine("Created {0}", product.GetType().Name);
        }
    }
    /// <summary>
    /// A 'ConcreteCreator' class
    /// </summary>

    class ConcreteCreatorA : Creator
    {
        public override Product FactoryMethod()
        {
            return new ConcreteProductA();
        }
    }
    /// <summary>
    /// A 'ConcreteCreator' class
    /// </summary>
    class ConcreteCreatorB : Creator
    {
        public override Product FactoryMethod()
        {
            return new ConcreteProductB();
        }
    }
}


2009-11-12 11:43 | winter-cn      

#130楼[楼主]  回复 引用 查看   

@winter-cn
修改的代码,的确有细微的差异,但我试着用你的方法去更改我《大话》中的代码,却发现了问题,我给你邮件了,你帮我改改。

大家都是技术爱好者,谈不上前辈后辈,有技术多讨论,共同提高是好事情,不用那么客气。
2009-11-12 12:39 | 伍迷      

#131楼  回复 引用 查看   

@伍迷
// Factory Method pattern -- Structural example  
using System;

namespace DoFactory.GangOfFour.Factory.Structural
{
    class MainApp
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>

        static void Main()
        {

            // An array of creators
            ZuoHaoShi[] haorenhaoshi = new ZuoHaoShi[2];

            haorenhaoshi[0] = new VolunteerZuoHaoShi();
            haorenhaoshi[1] = new UndergraduatedZuoHaoShi();

            // Iterate over creators and create products

            foreach (ZuoHaoShi zuohaoshi in haorenhaoshi)
            {
                zuohaoshi.Do();
            }

            // Wait for user
            Console.ReadKey();
        }
    }

    /// <summary>
    /// The 'Product' abstract class
    /// </summary>

    abstract class LeiFeng
    {
        public virtual void Sweep()
        {
            Console.WriteLine("扫地");
        }
        public virtual void BuyRice()
        {
            Console.WriteLine("买米");
        }
        public virtual void Wash()
        {
            Console.WriteLine("洗衣");
        }
    }
    /// <summary>
    /// A 'ConcreteProduct' class
    /// </summary>

    class Volunteer : LeiFeng
    {
        public override void Sweep()
        {
            Console.WriteLine("志愿者扫地");
        }
        public override void BuyRice()
        {
            Console.WriteLine("志愿者买米");
        }
        public override void Wash()
        {
            Console.WriteLine("志愿者洗衣");
        }
    }
    /// <summary>
    /// A 'ConcreteProduct' class
    /// </summary>
    class Undergraduated : LeiFeng
    {
        public override void Sweep()
        {
            Console.WriteLine("学生扫地");
        }
        public override void BuyRice()
        {
            Console.WriteLine("学生买米");
        }
        public override void Wash()
        {
            Console.WriteLine("学生洗衣");
        }
    }
    /// <summary>
    /// The 'Creator' abstract class
    /// </summary>

    abstract class ZuoHaoShi
    {
        public abstract LeiFeng GetLeiFeng();//Factory Method!
        public void Do()
        {
            LeiFeng product = GetLeiFeng();
            product.Sweep();
            product.Wash();
            product.BuyRice();
        }
    }
    /// <summary>
    /// A 'ConcreteCreator' class
    /// </summary>

    class VolunteerZuoHaoShi : ZuoHaoShi
    {
        public override LeiFeng GetLeiFeng()
        {
            return new Volunteer();
        }
    }
    /// <summary>
    /// A 'ConcreteCreator' class
    /// </summary>
    class UndergraduatedZuoHaoShi : ZuoHaoShi
    {
        public override LeiFeng GetLeiFeng()
        {
            return new Undergraduated();
        }
    }
}


2009-11-12 13:56 | winter-cn      

#132楼  回复 引用 查看   

大体的意思是把原来在Main函数中的代码放到一个类的方法中 然后把工厂方法也作为这个类的虚方法
2009-11-12 13:59 | winter-cn      

#133楼[楼主]  回复 引用 查看   

OK,基本上就是
product.Sweep();
product.Wash();
product.BuyRice();
是在客户端程序还是在工厂类里的问题,你把三个动作用了一个Do()方法来包装。这样的写法不是不可以,但却失去了灵活性。如果我只想Sweep,或者只想Wash(),你如何办呢?

还有就是这样就等于,
abstract class ZuoHaoShi
{
public abstract LeiFeng GetLeiFeng();//Factory Method!
public void Do()
{
LeiFeng product = GetLeiFeng();
product.Sweep();
product.Wash();
product.BuyRice();
}
}
必须要知道Sweep,Wash,BuyRice方法,这显然是耦合性过高了。我做为一个工厂类,为什么一定要知道产品的方法呢?假如哪天LeiFeng类要增加BuySauce方法,是否还要去修改这个ZuoHaoShi类?

从目前来看,我书中的讲解是没有错的,希望我的解释你可以明白。
2009-11-12 14:52 | 伍迷      

#134楼  回复 引用 查看   

@伍迷
OK 问题就出现在这里 你始终把ZuoHaoShi看做一个工厂类 但是实际上它不是工厂类
从重构的角度 我们要把某个设计重构到工厂方法,Creator(这个例子中是ZuoHaoShi)应该是一个已经存在的类

也就是说 工厂方法模式是给已经存在的类添加一个虚方法来创建对象

如果创建过程在一个静态函数(如main)中 我们就没有办法使用工厂方法, 这就是你觉得大话中的场景难以修改的原因。

请看GoF中的适用性一段:
引用
1) 当一个类不知道它所必须创建的对象的类的时候。
2) 当一个类希望由它的子类来指定它所创建的对象的时候。
3) 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
2009-11-12 15:34 | winter-cn      

#135楼[楼主]  回复 引用 查看   

@winter-cn
这就过于形式了。

关键在于是否达到了对修改关闭,对扩展开放等原则。目前来看,你给我的代码没有实现这个原则。

我的代码已经实现了开闭原则。希望你可以改造我的代码,哪怕你改动大一些,不要用main函数调用,通过其它类来实现。

一切用代码说话吧。
2009-11-12 16:01 | 伍迷      

#136楼  回复 引用 查看   

引用伍迷:
@winter-cn
这就过于形式了。

关键在于是否达到了对修改关闭,对扩展开放等原则。目前来看,你给我的代码没有实现这个原则。

我的代码已经实现了开闭原则。希望你可以改造我的代码,哪怕你改动大一些,不要用main函数调用,通过其它类来实现。

一切用代码说话吧。

我发的代码貌似是符合OCP的啊 你可以自由扩展产品(学雷锋的人) 并且创建对应的ZuoHaoShi的子类

你没有说哪里不符合OCP,我猜大概是指这里吧:
LeiFeng product = GetLeiFeng();
product.Sweep();
product.Wash();
product.BuyRice();
这一段不论如何都会在某处出现一次 即使写在main里面也是不可修改的

你看GoF的例子就知道了 CreateMaze跟那一堆Make显然是在一个类里面的 CreateMaze的内容也是一堆依赖产品的代码

其实我的代码完全是按照GoF本意来写的 就算不符合也不怪我啊 哈哈
这里开个玩笑 其实工厂方法还是符合的基本原则的
2009-11-12 16:08 | winter-cn      

#137楼[楼主]  回复 引用 查看   

@winter-cn
因为ZuoHaoShi这个抽象类里出现product.Sweep();product.Wash();product.BuyRice();意味着这个类会因为product的更改而更改。这显然违背了单一职责原则。当然,因为product更改,就要改动ZuoHaoShi,也就违背OCP.

另外
LeiFeng product = GetLeiFeng();
product.Sweep();
product.Wash();
product.BuyRice();
从来没规定要同时执行,分开执行也是有需求的。
2009-11-12 16:22 | 伍迷      

#138楼  回复 引用 查看   

引用伍迷:
@winter-cn
因为ZuoHaoShi这个抽象类里出现product.Sweep();product.Wash();product.BuyRice();意味着这个类会因为product的更改而更改。这显然违背了单一职责原则。当然,因为product更改,就要改动ZuoHaoShi,也就违背OCP.

另外
LeiFeng product = GetLeiFeng();
product.Sweep();
product.Wash();
product.BuyRice();
从来没规定要同时执行,分开执行也是有需求的。

即使出现在main里面 它没法符合OCP的啊
product.Sweep();
product.Wash();
product.BuyRice();
你要明白ZuoHaoShi和LeiFeng并非模式的一部分,而是假定为业务逻辑所必须的函数。你应该把ZuoHaoShi视为Client。

请你你把你原有的main函数的内容改成非静态的方法 这样就可以应用模板方法了
2009-11-12 16:49 | winter-cn      

#139楼[楼主]  回复 引用 查看   

@winter-cn
关于模式的讨论已经铺天盖地,的确是很难达成一个完全统一的认识。我想这个问题我们也就到此为至吧。我可能没能力让你能信服,而就目前而言,你的说法也没法让我修改原有的写法。

其实到底如何用设计模式和这样用是不是某个设计模式并不重要,重要的是这样做是否真的满足了那几个设计原则。而满足设计原则的目的,就是为了让代码更容易维护、容易扩展、可以复用等。只要你写的代码是可以达到这样要求,我觉得就是非常不错的代码。

为什么我不是说最优秀的,而只是非常不错。因为即使这样的代码,也未必是最有效率的,很多时候,过分在意用某个设计模式是有过度设计的嫌疑。刚刚够用,又有适当的可扩展可维护性的代码才是最最实在的代码。

这的确很难做到的,需要不断的学习和编程,我们都应该朝着这个方向持续的努力去达到这样的高度。
2009-11-12 17:15 | 伍迷      

#140楼  回复 引用 查看   

第十六页public Metabolism (Oxygen oxygen,Water water)这个是错的吧,应该是public void Metabolism (Oxygen oxygen,Water water)
2010-04-12 19:43 | Shikiro      

#141楼[楼主]  回复 引用 查看   

@Shikiro
它是构造函数,所以不需要void。依赖关系就意味着,在构造时就需要知道,所以必须写在构造函数中。这不是错误,谢谢!
2010-04-13 09:10 | 伍迷      

#142楼  回复 引用   

程杰老师你好,我是《大话设计模式》的一名读者
书写得很好 赞扬的人很多
赞扬的话我也就不多说了

这本书图书馆一到手就在看 目前还是在仔细品味附录的内容
发现一点小错误

@Page352
子类重写父类的protected虚方法时错误
原父类方法 protected virtual string getShoutSound(){...}
子类方法 public override string getShoutSound(){...} 此处错误
编译器错误提示:cannot change access modifiers when overriding 'protected' inherited member
应该为: protected override string getShoutSound(){...}

实在不知道怎么联系你 只好发在这了
十分感谢你的这本书
2010-05-27 13:55 | Emerson421[未注册用户]

#143楼[楼主]  回复 引用 查看   

@Emerson421
2.12 P352 中间四段代码,分别是Cat、Dog、Cattle、Sheep四个类中“public override string getShoutSound() ” ,其中“public”应改为"protected" (beach-boy 提供)

此错误在勘误中已经有,在后期的印刷书中已经更正,您可能是早期出版的图书,建议您仔细对照勘误修改后,再阅读。谢谢
2010-06-09 17:21 | 伍迷      

#144楼  回复 引用 查看   

引用伍迷:
@Shikiro
它是构造函数,所以不需要void。依赖关系就意味着,在构造时就需要知道,所以必须写在构造函数中。这不是错误,谢谢!


书上是
abstract class Animal
{
public Metabolism(Oxygen oxygen,Water water){}
}

如果是构造函数,那Animal应该是Metabolism吧,而且如果按照你说的是构造函数,那前面的类图不是也错了?
2010-06-18 17:03 | Shikiro      

#145楼  回复 引用 查看   

P145页,客户端代码多了一句
User user = new User():
2010-06-18 17:13 | Shikiro      

#146楼[楼主]  回复 引用 查看   

@Shikiro
非常抱歉,经过我的仔细分析,您说得没错,是我没有看清楚。应该是少了一个void,准确的应该是public void Metabolism (Oxygen oxygen,Water water),它并不是构造函数。

引用Shikiro:
P145页,客户端代码多了一句
User user = new User():


这一句不能少,因为后面有一句iu.Insert(user);
2010-06-19 08:49 | 伍迷      

#147楼  回复 引用 查看   

《大话》的216页,讲解单例模式时有一句话“实用类不能用于继承多态,而单例虽然实例唯一,确实可以有子类来继承”
单例类只有private的构造函数,如何被继承
单例类的子类实例化时需要调用父类的构造函数,由于父类private,根本无法调用
2010-10-11 19:31 | 王晓营      

#148楼[楼主]  回复 引用 查看   

@王晓营
如果硬要实现单例的继承,需要将父类的构造函数的private改成protected。
不过通常单例都不去继承实现功能,至少我从来没这么做过,没办法给你更多的建议。
2010-10-13 10:53 | 伍迷      

#149楼  回复 引用 查看   

2010年4月份第八次版P185的游戏角色类,其中的代码第一句:
class 游戏角色
应为
class GameRole(在P180页写的是GameRole)。
2010-12-19 22:47 | 秦萌      

#150楼[楼主]  回复 引用 查看   

@秦萌
感谢您的指正,这的确是一个错误。
2010-12-21 12:29 | 伍迷      

#151楼  回复 引用 查看   

@伍迷
呵呵,您客气了,这个也不能算错误,其实这个地方说不说都无所谓的,只是想本书变得更好内容更一致,我们是来向您学习的,学习您的编程思想和风格,这才是我们最想要的,希望看到更多此类的文章,我会一直关注下去的。
2010-12-30 23:42 | 秦萌      

#152楼  回复 引用 查看   

2010年4月份第八次版P255的Static void Main(String[] args),其中的代码第二句:
“金利”应为“经理”
“宗剑”应为“总监”
“钟精励”应为总经理
P286的“结果显示里”也同样
2011-01-20 17:19 | 秦萌      

#153楼[楼主]  回复 引用 查看   

@秦萌
这是故意为之,这三个都是人名,同时也用谐音代表了他们的身份。
2011-01-21 13:43 | 伍迷      

#154楼  回复 引用 查看   

@伍迷
哦,原来是这样呀,只是个人的感觉有点怪,呵呵,听惯了,王经理,李总监,贺总,之类的了,这个谐音容易让人觉得是错别字,每个人的理解不相同罢了。
2011-01-21 18:05 | 秦萌      

#155楼  回复 引用 查看   

麻烦老师解答下两个疑问
一.p106类图,基金类聚合股票类,p108又变成了基金类关联股票类
代码基本相同,不解也不知是否错误
二.前面类图的知识提到初始化时,实例化对象(p15鸟和翅膀的例子)。这个是组合关系.书中的例子也是构造时就实例化对象,怎么是关联关系而不是组合关系呢。新手对此十分疑惑,望解答谢谢!
2011-02-06 18:25 | 今晚在线      

#156楼  回复 引用 查看   

第2章的例子中间的满300“返”100,个人意见可能会引起误解。因为多数商场使用这种营销策略时是返回相应面值的购物券而不会直接从货款中抵扣应支付的金额。建议直接改成满300“减”100。
2011-02-10 13:24 | 小唐菜      

#157楼[楼主]  回复 引用 查看   

@小唐菜
有的商场是返钱,有的是返券。其实这并不重要,我这里只是一个小例子,没有商场会用我写的程序去作为商场的打折程序。
2011-02-10 14:22 | 伍迷      

#158楼  回复 引用 查看   

另有一处疑问:P50页第二个注释框和P51页第一行“从外‘类’”这个外类怎么理解,是“外部”之误吗
2011-02-11 09:38 | 小唐菜      

#159楼  回复 引用 查看   

@今晚在线
前面是小菜提出的设计模式,后面是大鸟教他的新模式。
2011-03-02 12:06 | 秦萌      

#160楼  回复 引用 查看   

博主,我想问一个比较简单的问题。就是2010年4月份第八次版P14的依赖与关联,UML画得比较清楚,一看就懂了,但是我无法从代码上去区分它到底是依赖还是关联,请多举一两个例子来说明一下,谢谢。
2011-03-02 12:13 | 秦萌      

#161楼  回复 引用 查看   

2010年4月份第八次版
第九章“原型模式”P86
(1)最后一段话,中间有句话“所以对于值类型,没什么问题,对引用类型,就只是复制了引用”
(2)倒数第二段的结果显示那里,大鸟的年龄是有变化的
从上面两个条件可以推出:P85的
private string age;
应为private int age;
//设置个人信息 的方法
public void SetPersonalInfo(string sex,string age)
应为
public void SetPersonalInfo(string sex,int age)
那么对应的要调用的地方,P86客户调用代码那里
a.SetPersonalInfo("男","29");
应为
a.SetPersonalInfo("男",29);

c.SetPersonalInfo("男","24");
应为
a.SetPersonalInfo("男",29);
2011-03-03 22:21 | 秦萌      

#162楼  回复 引用 查看   

a.SetPersonalInfo("男",29);
这个写错了,
a.SetPersonalInfo("男",24);
2011-03-03 22:22 | 秦萌      

#163楼  回复 引用 查看   

哦,不好意思,您的那个有关简历的姓名、性别、年龄在Resume类里面,并没有分离出来,所以代码没有问题。
2011-03-03 22:28 | 秦萌      

#164楼  回复 引用 查看   

找到了两个不算错误的“错误”,只是觉得改了让本书变得更专业。
2010年4月份第八次版 第二个方框的标记解释应与与第三个方框标记的解释对调。
第20章“迭代器模式”P206的第一篇的代码的最下面的代码的第一句,context.演奏文本
但是在P287写着的是context.PlayText,而且其它调用的地方也是写着PlayText。


昨天总算把大话设计模式看完了,心里真的很感激博主,因为这本书给我了软件思想上很大很大的提升,特别觉得解释器模式那章很吸引人,这本书甚至决定了我以后开发软件的思想,所以想对您说声谢谢!
2011-03-23 23:38 | 秦萌      

#165楼[楼主]  回复 引用 查看   

@秦萌
感谢您的指正。您得到两个地方,第一个错误我没看明白。第二个,应该将“演奏文本”改为“PlayText”,谢谢!

如果书觉得不错,希望可以到如豆瓣等网站写写书评,无论褒贬都是对其他读者有指导意义!

希望继续支持我的图书,我的新书《大话数据结构》将于5月出版,请关注。
2011-03-24 09:24 | 伍迷      

#166楼  回复 引用 查看   

不好意思,白天在上班。我一定会继续支持您的著作的,对于这个大话设计模式,只能用相见恨晚来形容!
昨天没有说清楚第一个“错误”,重新说明下,呵呵:
public override object CurrentItem()
{
return aggregate[current];--此标记的说明:判断当前是否遍历到结尾,到结尾返回true;(应为返回当前的聚集对象)
}
public override bool IsDone()
{
return current<0?true:false;--此标记的说明:返回当前的聚集对象(应为判断当前是否遍历到结尾,到结尾返回true)
}

非常期待您五月份的书籍,承蒙您看得起我,我一定会写下真实的大话设计模式带给我的帮助的!
2011-03-24 21:23 | 秦萌      
评论共2页: 上一页 1 2 
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

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

0 994047 hSW/2Kr4v/8=

导航

公告

    《大话数据结构》第三次印刷已将勘误中的错误修正,预计在2011年12月在各大网上书店中有售。具体时间由网店决定,我也不清楚,如果有买到的朋友能否给我发封邮件呀。再次向已经购买第一二次印刷的读者说一声抱歉,给您要花时间修正错误添麻烦了,当然您们在花费二十多分钟的修改后就能尽早阅读本书,也算是有遗憾后值得欣慰的地方!


联系邮箱:chengjielong#163.com
(中间“#”换成“@”)


新浪微博:http://weibo.com/cj723


本人《大话数据结构》2011年6月简体中文版由清华大学出版社出版,繁体中文版由台湾悦知文化出版



简体中文版


繁体中文版


本人因《大话设计模式》而获得51CTO网站主办的"2008年十大IT图书最佳原创作者奖" ;《大话设计模式》获互动出版网评选的2008年度十大畅销经典第4名;当当网计算机/网络类2008年度畅销榜第6名



简体中文版


繁体中文版
昵称:伍迷
园龄:5年5个月
荣誉:推荐博客
粉丝:669
关注:18

搜索

 

常用链接

随笔分类(165)

随笔档案(138)

相册

朋友

积分与排名

  • 积分 - 535943
  • 排名 - 107

最新评论

阅读排行榜

推荐排行榜