得墨忒耳(迪米特)定律(Law of Demeter,缩写LoD)亦称为“最少知识原则(Principle of Least Knowledge)”,是一种软件开发的设计指导原则,特别是面向对象的程序设计。得墨忒耳(迪米特)定律是松耦合的一种具体案例。该原则是美国东北大学在1987年末在发明的,可以简单地以下面任一种方式总结:
1. 每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元;
2. 每个单元只能和它的朋友交谈:不能和陌生单元交谈;
3. 只和自己直接的朋友交谈。
这个原理的名称来源于希腊神话中的农业女神,孤独的得墨忒耳。
很多面向对象程序设计语言用"."表示对象的域的解析算符,因此得墨忒耳定律可以简单地陈述为“只使用一个.算符”。因此,a.b.Method()违反了此定律,而a.Method()不违反此定律。一个简单例子是,人可以命令一条狗行走(walk),但是不应该直接指挥狗的腿行走,应该由狗去指挥控制它的腿如何行走。----WIKIPIDIA
个人的理解:
面向对象的程序设计中,对象与对象之间尽量相互独立,具体对象的行为由具体的对象去完成,而不是由某个对象去指定另一个对象去实施行为而且是具体的行为。迪米特法则,核心的思想就是,要求我们在设计的时候,尽量避免类与类之间的耦合,弱化耦合关系可以提升复用率,但是这样的话,会产生中间的跳转类等,导致系统复杂。实际使用的过程中尽量在保证可读性与复杂性较低的情况下,按照迪米特法则去弱化类与类之间的耦合关系(高内聚、低耦合)。
下面看这样的一个例子:
场景介绍:想象一下,你是这家的主人,雇佣了管家帮你安排一些家务事,还雇佣了一些佣人去帮你完成管家吩咐的家务事。你想吃饭,这时候,需要向管家吩咐一下,然后你就不需要管了,具体谁去做饭这不需要你去关系,你只需要知道,待半个小时左右,我看到餐桌上有饭,你可以去品尝就好了,这样才是比较合理的事情。
直接看代码:
佣人:
- public class Maid {
- private String maidName;
- public Maid() {
- super();
- }
- public Maid(String maidName) {
- super();
- this.maidName = maidName;
- }
- public void cook(){
- System.out.println(this.maidName + ">>做饭!");
- }
- }
- public class Butler {
- public void cook(List<Maid> maidList){
- for (Maid maid : maidList) {
- maid.cook();
- }
- }
- }
- public class Master {
- public void cookCommand(Butler butler){
- List<Maid> maidList = new ArrayList<Maid>();
- for(int i = 0; i < 2; i++){
- maidList.add(new Maid("maid" + i));
- }
- butler.cook(maidList);
- }
- }
问题来了,这里的设计的时候,是不是太不合理了,你作为一个主人,管的太多了,因为你要去创建好一些佣人,交给管家去吩咐,这个任务对你来说显然是多余的,因为有管家在,你不用去做这么多事情,你只需要跟管家说,管家,我想吃点东西,管家接到命令之后,去找来几个佣人,然后去给你做饭。这样才是好的设计。
上面的这个设计违背了迪米特法则,因为,Master与Butler、Maid是层级的关系,在Master这个类中,只需要去管理Butler而Butler中去管理Maid,通俗来说是Master给Butler吩咐任务,Butler接到任务后然后再给Maid分配任务。
我们按照这个思路再来设计一下上面的例子。
- public class Master {
- public void cookCommand(Butler butler){
- butler.cook();
- }
- }
- public class Butler {
- public List<Maid> getMaidList(){
- List<Maid> maidList = new ArrayList<Maid>();
- for(int i = 0; i < 2; i++){
- maidList.add(new Maid("maid" + i));
- }
- return maidList;
- }
- public void cook(){
- List<Maid> maidList = getMaidList();
- for (Maid maid : maidList) {
- maid.cook();
- }
- }
- }
这样设计的话,你会发现,Master不用跟Maid打交道,而是和Butler打交道,这样的话,减少了类与类之间不必要的耦合,使得系统更稳定,扩展更容易。
根据迪米特法则设计类的时候,尽量降低非朋友类之间的耦合。
源代码:源代码下载