迪米特原则
一,介绍
1.前言
迪米特原则(Law of Demeter,简称LoD)也被称为最少知识原则(Least Knowledge Principle,LKP),是面向对象设计的一种重要原则。迪米特原则的核心思想是尽量减少对象之间的交互,使得系统中的模块能够相对独立地变化。
迪米特原则最初是由Ian Holland和Richard Gabriel在1987年的OOPSLA(Object-Oriented Programming, Systems, Languages & Applications)会议上提出的,并由C. J. Date和Barbara Liskov进一步发展完善。迪米特原则被广泛应用于软件设计、系统架构等领域,并成为面向对象设计中的一个重要原则之一。
迪米特原则的核心思想可以用“不要和陌生人说话”来形象地概括。也就是说,一个对象应该尽可能地减少与其他对象之间的直接交互,只与它所认识的朋友类进行交互。朋友类包括两种:一种是当前对象本身,另一种是当前对象所持有的对象(成员变量)、方法参数中传入的对象、或内部创建的对象等。
迪米特原则的优点在于:
- 降低类之间的耦合度,使得系统更加灵活,易于维护和扩展。
- 促进类的复用,提高代码的重用性和可读性。
- 提高系统的稳定性和安全性,减少由于类之间直接交互而带来的风险。
迪米特原则的实现主要有以下几种方式:
1. 只与朋友类交互。即一个类只与自己的成员、参数、返回值中所涉及到的类进行交互,而不直接与其他类进行交互。
2. 封装类的内部细节。即一个类不应该暴露其内部的实现细节,只提供必要的接口进行交互。
3. 引入第三方代理。即通过引入一个中间类来封装和隔离两个不同的类之间的交互。
2.何时使用米莱迪原则
- 当一个类或模块承担了过多的功能或任务,导致其代码的可读性、可维护性和可测试性降低时,我们可以使用米莱迪原则来拆分这个类或模块,使其承担更加明确的单一责任。
- 当我们需要修改一个类或模块时,如果这个类或模块承担了多种不相关的责任,那么修改的影响范围可能会很大,也容易引入错误。在这种情况下,使用米莱迪原则将这个类或模块拆分成多个承担单一责任的小模块,可以降低修改的风险和成本。
- 当我们需要进行代码重构时,根据米莱迪原则对代码进行重组和重构,可以使代码更加清晰、易于理解和维护。同时,这也可以避免模块之间的耦合和依赖过度,提高系统的可扩展性和灵活性。
二,代码示例
下面以一个简单的例子来说明迪米特原则:
public class Person { private String name; private List<Friend> friends; public Person(String name, List<Friend> friends) { this.name = name; this.friends = friends; } public void sendGifts(Friend friend) { System.out.println(name + " is sending gifts to " + friend.getName()); } public void sendGiftsToAll() { for (Friend friend : friends) { sendGifts(friend); } } } public class Friend { private String name; public Friend(String name) { this.name = name; } public String getName() { return name; } }
在这个例子中,`Person`类尝试给自己的好友们送礼物。`Person`类持有一个`List`类型的`friends`成员变量,表示它的朋友列表。在`sendGiftsToAll`方法中,`Person`类遍历它的所有好友,并调用`sendGifts`方法给每个好友送礼物。
然而,这个设计违反了迪米特原则。`Person`类直接操作`Friend`对象,即它和陌生的`Friend`类直接进行交互。这样做的问题在于`Person`类对`Friend`类的依赖过于紧密,增加了系统的耦合性。如果系统需要修改`Friend`类或者更换成其他类型的好友,那么就会导致`Person`类的修改,从而影响整个系统的稳定性和安全性。
为了符合迪米特原则,我们可以通过引入中间类来隔离`Person`类和`Friend`类之间的交互。具体做法是在`Person`类中引入`GiftSender`类,让`GiftSender`类来负责处理礼物的送出:
public class Person { private String name; private List<Friend> friends; public Person(String name, List<Friend> friends) { this.name = name; this.friends = friends; } public void sendGiftsToAll(GiftSender giftSender) { for (Friend friend : friends) { giftSender.sendGifts(name, friend); } } } public class GiftSender { public void sendGifts(String senderName, Friend friend) { System.out.println(senderName + " is sending gifts to " + friend.getName()); } }
在这个设计中,`Person`类不再直接操作`Friend`对象,而是通过`GiftSender`类来进行交互。`GiftSender`类只对外公开一个方法`sendGifts`,它是`Person`类的朋友类,负责处理礼物的送出。这样做的好处在于,如果系统需要更换成其他类型或者更改礼物送出的方式,只需要修改`GiftSender`类即可,`Person`类无需做出任何修改,从而减少了系统维护的成本。
总之,迪米特原则要求我们尽量减少对象之间的交互,使得系统中的模块能够相对独立地变化。通过遵循迪米特原则,我们可以降低类之间的耦合度,提高系统的灵活性、扩展性和可维护性,从而实现更加优秀的软件设计。
三,优缺点
迪米特原则(Law of Demeter,LoD),也被称为最少知识原则(Principle of Least Knowledge),是面向对象设计的一个原则,它强调一个对象应该尽量减少与其他对象之间的交互,只与直接的朋友进行通信。迪米特原则具有以下优点和缺点:
优点:
1. 降低耦合度:迪米特原则要求一个对象只与其直接的朋友发生交互,而不需要了解其他对象的内部细节。这降低了对象之间的耦合度,使得系统更加灵活、可扩展和易于维护。
2. 提高模块的独立性:根据迪米特原则,对象只与其直接的朋友进行通信,而不需要与其他对象产生联系。这使得每个模块具有较高的独立性,可以更容易地被理解、修改和重用。
3. 增强了系统的可测试性:由于对象之间的耦合度降低,模块间的依赖减少,提高了系统的可测试性。我们可以更容易地对单个模块进行测试,而不需要关注其依赖的其他模块。
4. 减少了代码的脆弱性:当一个对象只与其直接的朋友进行通信时,即使其他对象发生变化,也不会对该对象产生直接的影响。这减少了代码的脆弱性,使得系统更加健壮和稳定。
缺点:
1. 增加了消息传递的复杂性:迪米特原则要求对象只与其直接的朋友进行通信,这可能增加了消息传递的复杂性。需要引入额外的中间对象作为消息的传递者,导致系统的结构变得复杂。
2. 可能导致过多的中间对象:为了减少对象之间的直接交互,可能会引入过多的中间对象。这增加了系统的复杂性和维护成本,也会影响系统的性能。
3. 可能破坏封装性:迪米特原则强调对象只与其直接的朋友进行通信,这可能会泄露一些内部的实现细节,破坏了对象的封装性。
总结起来,迪米特原则通过降低对象之间的耦合度、提高模块的独立性和可测试性来改善软件系统的设计质量。然而,它也可能增加消息传递的复杂性、引入过多的中间对象,并破坏封装性。因此,在应用迪米特原则时需要权衡利弊,根据具体的设计需求和实际情况选择适合的设计方案。