1.背景
1987年秋天由美国Northeastern University的Ian Holland提出,被UML的创始者之一Booch等普及。后来,因为在经典著作《 The Pragmatic Programmer》而广为人知。
2.概念
迪米特法则(Law of Demeter)又叫作最少知识原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。英文简写为: LOD。
通俗的讲:
-
不该知道的不要知道;
-
一个类应该保持对其它对象最少的了解,只和朋友通信,不和陌生人说话;
-
降低类之间的耦合度;
-
从依赖者的角度来说,只依赖应该依赖的对象;
-
从被依赖者的角度说,只暴露应该暴露的方法;
设计原则:
-
在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标;
-
在类的结构设计上,尽量降低类成员的访问权限;
-
在类的设计上,优先考虑将一个类设置成不变类;
-
在对其他类的引用上,将引用其他对象的次数降到最低;
-
不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法);
-
谨慎使用序列化(Serializable)功能;
3.案例
需求:租客想通过中介找房子,租客想要一个20平、2000一个月的。
方案一(不满足迪米特原则):把所有房源都给租客,租客自己选
/// <summary>
/// 房源
/// </summary>
public class Room
{
private int are;
private int pay;
public int getAre()
{
return are;
}
public void setAre(int are)
{
this.are = are;
}
public int getPay()
{
return pay;
}
public void setPay(int pay)
{
this.pay = pay;
}
}
/// <summary>
/// 中介
/// </summary>
public class Mediator
{
private List<Room> allRooms = new List<Room>();
/// <summary>
/// 初始化房源
/// </summary>
public Mediator()
{
for (int i = 0; i < 10; i++)
{
Room room = new Room();
room.setAre((i + 1) * 5);
room.setPay((i % 4 == 0 ? 1 : i % 4) * 1000);
allRooms.Add(room);
}
}
/// <summary>
/// 获取所有房源
/// </summary>
/// <returns></returns>
public List<Room> GetAllRooms()
{
return allRooms;
}
}
/// <summary>
/// 租客
/// </summary>
public class Tenant
{
public static void RentRoom(Mediator mediator)
{
// 通过中介获取所有房屋
List<Room> allRoom = mediator.GetAllRooms();
foreach(Room room in allRoom)
{
if (IsSuitable(room))
{
Console.WriteLine("房屋找到了");
}
}
}
/// <summary>
/// 判断房子是否满足客户需求
/// </summary>
/// <param name="room"></param>
/// <returns></returns>
private static bool IsSuitable(Room room)
{
// 筛选房屋
return true;
}
}
{
//LOD:迪米特原则
Tenant.RentRoom(new Mediator());
}
代码分析:
以上的方案是中介直接把所有的房源全部提供给顾客,其中就包含不满足租客条件的房源,这就增加了租客和房源直接的耦合度。
方案二(满足迪米特原则):先按照要求把房源筛选出来,给租客
/// <summary>
/// 房源
/// </summary>
public class Room
{
private int are;
private int pay;
public int getAre()
{
return are;
}
public void setAre(int are)
{
this.are = are;
}
public int getPay()
{
return pay;
}
public void setPay(int pay)
{
this.pay = pay;
}
}
/// <summary>
/// 中介
/// </summary>
public class MediatorLOD
{
private List<Room> allRooms = new List<Room>();
public MediatorLOD()
{
for (int i = 0; i < 10; i++)
{
Room room = new Room();
room.setAre((i + 1) * 5);
room.setPay((i % 4 == 0 ? 1 : i % 4) * 1000);
allRooms.Add(room);
}
}
/// <summary>
/// 找出符合租客要求的房子
/// </summary>
/// <param name="are"></param>
/// <param name="pay"></param>
/// <returns></returns>
public Room RentRoom(int are, int pay)
{
// 通过中介获取所有房屋
foreach(Room room in allRooms)
{
if (IsSuitable(room, are, pay))
{
return room;
}
}
return null;
}
/// <summary>
/// 判断房源是否满足客户的要求
/// </summary>
/// <param name="room"></param>
/// <param name="are"></param>
/// <param name="pay"></param>
/// <returns></returns>
private bool IsSuitable(Room room, int are, int pay)
{
// 筛选房屋
return true;
}
}
/// <summary>
/// 租客
/// </summary>
public class TenantLOD
{
/// <summary>
/// 获取满足条件的房源
/// </summary>
/// <param name="mediator"></param>
public static void RentRoom(MediatorLOD mediator)
{
Console.WriteLine(mediator.RentRoom(20, 2000));
}
}
{
//LOD:迪米特原则
Tenant.RentRoom(new Mediator());
}
代码分析:
相比方案一,当前方案把筛选的过程放到了租客能联系到的中介身上,中介处理房源,而租客和房源的联系微乎其微,这就利用了LOD 原则,降低了租客和房源的耦合度,租客只看到符合条件的房源就可以了。
4.优缺点
优点:
-
降低了类之间的耦合度,使类与类之间保持松散的耦合关系;
-
由于耦合度降低,提高了模块的相对独立性;
-
提高类的可复用性和系统的扩展性;
缺点:
-
迪米特法则是一种面向对象系统设计风格的一种法则,尤其适合做大型复杂系统设计指导原则。但是也会造成系统的不同模块之间的通信效率降低,使系统的不同模块之间不容易协调等。