- This topic is empty.
-
AuthorPosts
-
-
2010年09月3日 at 2:00 pm #1085
Todd
Member目前,我能够识别并避免违背迪米特法则,但是总感觉对迪米特法则的认识深度还不够,还不能说清楚到底迪米特法则本质上意味着什么。我目前思考的结果是:
OOP中,对象间的交互是消息传递模型,而消息是值语义的;而obj.GetAnotherObject()的结果是引用,违背了对象消息传递模型。所以,违背迪米特法则的设计其实是不符合OOP的。
-
2010年09月3日 at 4:19 pm #1300
hui
Keymaster迪米特法则(以下简称LoD)提倡一个类尽量不要与其间接关联的类发生直接对话。这一方面有助于减少类之间的关联,从而降低系统的耦合度;另一方面有助于界定职责范围,从而增强了系统的内聚度。从消息传递的角度看,LoD可看作一种对象交流原则:只吩咐不询问(tell, don’t ask)(可参见 http://www.pragprog.com/articles/tell-dont-ask 和 http://www.c2.com/cgi/wiki?TellDontAsk )。当然,LoD最终目的是为了降低软件的脆弱性、增强软件的可维护性。
LoD虽然不是必须遵守的铁律,但一个有经验的程序员在违背它时,会听到身后的警告声:你知道得太多了:)
-
2010年09月4日 at 8:00 am #1301
Todd
Member谢谢,推荐的文章很好,看了之后我对LoD的认识加深了不少!
另外,还有一个意外的收获,即文中提到了CQRS。以前我觉得很多post condition/class invariant不容易在实际编程中表达,一个重要原因是assert语句不应该有副作用,现在我知道如果类的设计能采用CQRS的方式,那么就很容易写出无副作用的assert语句来表达post condition/class invariant。
另外,最近关于CQRS还看到一些持久化方面的应用,普通的持久化方案是基于对象内部状态的,而采用CQRS,把所有的commands持久化下来就得到了对象的状态以及状态历史。
-
2010年10月2日 at 3:30 am #1302
Todd
Member>>LoD虽然不是必须遵守的铁律,但一个有经验的程序员在违背它时,会听到身后的警告声:你知道得太多了:)
http://www.aspiringcraftsman.com/2008/06/distilling-law-of-demeter
这篇文章讲了LoD的思想也提到了LoD不是任何场合都适用。我想到一个例子:Company与CEO的关系,CEO ceo = company.GetCEO()是违反LoD的,但这又是领域模型所需要的。
我曾经想能不能把软件设计得像汽车一样,具有清晰地功能层次和子系统边界。后来发现现实的领域模型比机械结构要复杂得多,更接近于错综复杂的网状,而不是机械的树状结构。这种追求是一种理想的情况,但不是总能达到。
-
2010年10月2日 at 2:55 pm #1303
hui
Keymaster没错,现实中的模型经常是网状结构的,如何尽可能地减少非必要关联、横向或纵向分割复杂关联正是软件设计的最大挑战之一。
-
2011年01月12日 at 8:29 am #1304
Lumj
Member我很难理解tell,don’t ask这个原则
我看了在2L给出的文章,
That is, you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do
使外界能了解自己的状态不正是对象的职责吗?不知这个理解哪里有误?
不过我猜想是否这样:
首先,ask没问题,可是不该以ask的结果为依据对其tell
然后,”ask,decide,then tell”针对的是对象职责范围内的逻辑
我想到个例子:
if(someControl.isVisible())
someControl.hide();
就是对象的职责外泄,因为”在已经隐藏的情况下无须调用hide”是Control自然该管的,正确的做法是:
someControl.hideIfVisible();
而同样是”ask,decide,then tell”,却不可能将
if(someNumber.isLargerThan(100))
someNumber=100;
敛为Number.truncateIfLargerThanOneHundred供人调用,因为100这个数字在只谈论Number的时候是个magic number,它的语义是在Number以外才得以实现的
-
2011年01月12日 at 11:46 am #1305
hui
Keymaster用Number作例子是不恰当的,如果这个Number是基本类型的话。相反,如果Number包含足够的业务逻辑,那么magic number的处理正应该是Number的职责。
一个通俗的tell, don’t ask的例子是:要一只狗跑,不是dog.getLegs().run(),而是dog.run(),即不是指挥狗的腿来跑,而是由狗自己负责调用腿来跑。事实上,指挥者根本不在乎狗有没有腿,只在乎它能不能跑。至于它用腿跑,还是聪明到能用嘴控制某个机动车来跑,则是狗的职责,不是指挥者的职责。因此“tell, don’t ask”是一种良好的职责分工原则,能使代码保持合理的抽象层次划分。
可以这么理解:tell代表一个抽象的命令,而ask代表(被命令对象的)具体执行方法或步骤。
-
2011年01月12日 at 1:43 pm #1306
Lumj
Member“tell代表一个抽象的命令,而ask代表(被命令对象的)具体执行方法或步骤”
嗯,这样的话便容易理解了,我知道了
我本来的理解是一种荒唐的理解:
if(nameTextBox.getText()=="Lumj"){//ask,decide
alert("This is our admin's name,you cannot use it");
nameTextBox.setText(String.empty);//tell
}
-
2011年01月15日 at 9:24 am #1307
Lumj
Member最近对这个法则又有了更多的体会
LoD是PIE(Program intensively and expressively)原则的一种很直接的体现
intensively,and expressively,其实即是不要降级语义
要做什么事,就让对象对这种情况知情和付诸关注,而不要自己在对象外实现掉一层(更有甚者是若干层)高层语义,再把剩下的转发给对象
隐晦和拐弯抹角即意味着不受支持,不会在发生变化时被对象纳入考虑,从而脱节
象dog.legs.run()的情况即是:这条狗并不懂得run,是外界隐晦地告诉它的,”dog会run”这层语义即是名存实亡的,是Dog外部的一厢情愿
-
2011年01月15日 at 9:50 am #1308
hui
KeymasterPIE原则是“program intently and expressively”,intently与intensively不是一回事。你的说法虽然有些模糊,但还是抓住了一个要点,即:LoD涉及抽象层次问题(语义与抽象密切相关),一个对象尽量不要与不在同一抽象层次的另一对象打交道。比如,此处人(作为狗的命令者)与狗处于同一层次,但狗的腿则处于更下一层。人应当与狗打交道,而不是它的腿。
-
2011年01月15日 at 10:52 am #1309
Lumj
Member呃..原来我还搞错了一个词..
每次都是扫到这个词的,我迅雷不及掩耳地就以为那个词是intend变来的一个形容词,觉得这个词相当传神呢..
-
2011年01月18日 at 5:33 am #1310
Todd
Member>>一个对象尽量不要与不在同一抽象层次的另一对象打交道。
我认为C和C++的指针之所以危险,一个重要原因就是它同时具备了两个抽象层次,一是底层的内存地址;一是高层的对象引用。
-
2011年01月21日 at 3:16 am #1311
Lumj
Member对的
-
-
AuthorPosts
- You must be logged in to reply to this topic.