定义:迪米特法则也称为最少知识原则,一个对象应该对其他对象有最少的了解,迪米特法则的一个英文解释为: Only talk to your immediate friends (只和你最亲近的朋友交谈)。
一个类应该对自己需要耦合的类或者调用的类知道的最少,被耦合或调用的类内部逻辑跟自身无关,也不需要关心,只需要知道被耦合或者调用类提供的 public 方法或者属性变量。
迪米特法则的核心观念就是降低类间耦合。每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少)依赖关系。
狭义的迪米特法则
如果两个类不必彼此直接通信,那么两个类就不应该发生直接的相互作用,如果其中一个类必须调用另一个类的某些方法,可以通过第三者转发这个调用。
尽量减少 GetA().GetB().GetC() 此种调用。
朋友界定
(1) 当前对象自身(this)
(2) 以参数形式传入到当前对象方法中的对象
如下 B b 是 A 的朋友
public class A
{
public void SetB(B b)
{ }
}
public class B
{ }
(3) 当前对象的实例变量直接引用的对象
如下 C 引用 B对象, B b 是 C 的朋友
public class B
{
}
public class C
{
private B b;
}
(4) 当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友
D 类中变量 cList 是C类的一个聚集,则聚集中的所有C类对象都是D类对象的朋友
public class C
{
private B b;
}
public class D
{
private List<C> cList = new List<C>();
}
(5) 当前对象所创建的对象
E 类对象方法 CreateD() 创建的是 D 类对象,创建的 D类对象 d 是 E 类对象的朋友
public class D
{
private List<C> cList = new List<C>();
}
public class E
{
public D CreateD()
{
D d = new D();
return d;
}
}
狭义迪米特法则的缺点:
(1) 系统中出现大量小方法,这些方法仅仅是传递间接的调用,与系统的业务逻辑无关
(2) 遵循类之间的迪米特法则会是一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有之间的交互,但是这也造成系统的不同模块间的通讯效率降低,也会是系统的不同模块之间不容易协调。
外观模式、中介者模式就是迪米特法则的应用
广义的迪米特法则在类的设计上的体现:
(1) 优先考虑将一个类设计成不变类
(2) 尽量降低一个类的访问权限:如将类的访问权限限定在一个包、命名空间内
(3) 尽量降低成员的访问权限:如合理使用public、protected、private
下面以一个实例展示如何遵循迪米特法则
有一个设计公司
一个部门的负责人是 项目经理,项目经理管理部门内的 程序人员、美术人员、产品设计人员
一个客户,客户应该只负责跟项目经理提需求,项目经理根据需求将工作任务安排给不同人员
类比到迪米特法则中
项目经理的朋友们: 程序人员、美术人员、产品设计人员
客户的朋友:项目经理
客户 跟 程序人员、美术人员、产品设计人员 是陌生人
正常情况下,客户类对象是不允许访问、调用 程序人员、美术人员、产品设计人员 对象的
代码实现如下
// 添加命名空间,限制访问权限
namespace Company
{
// 项目经理
public class PM
{
// 引用程序人员,不允许通过 PM 对象访问该变量
private Program _program;
// 引用美术人员,不允许通过 PM 对象访问该变量
private Art _art;
// 引用产品人员,不允许通过 PM 对象访问该变量
private Product _product;
public PM()
{
// 直接在内部创建对象了
Program program = new Program();
SetProgram(program);
Art art = new Art();
SetArt(art);
Product product = new Product();
SetProduct(product);
}
// 添加引用对象
public void SetProgram(Program program)
{
_program = program;
}
// 添加引用对象
public void SetArt(Art art)
{
_art = art;
}
// 添加引用对象
public void SetProduct(Product product)
{
_product = product;
}
// 需求调用
public void DoSomething(string msg)
{
if (msg.CompareTo("programDemand") == 0)
{
_program.DoSomething(msg);
}
else if (msg.CompareTo("artDemand") == 0)
{
_art.DoSomething(msg);
}
else if (msg.CompareTo("productDemand") == 0)
{
_product.DoSomething(msg);
}
}
}
// 程序人员
public class Program
{
// 需求调用
public void DoSomething(string msg)
{
Console.WriteLine("程序人员:" + msg);
}
}
// 美术人员
public class Art
{
// 需求调用
public void DoSomething(string msg)
{
Console.WriteLine("美术人员:" + msg);
}
}
// 产品设计人员
public class Product
{
// 需求调用
public void DoSomething(string msg)
{
Console.WriteLine("产品设计人员:" + msg);
}
}
}
客户类实现如下
// 添加命名空间,限制访问权限
namespace Client
{
public class Client
{
public Client()
{
Company.PM pM = new Company.PM();
pM.DoSomething("programDemand");
pM.DoSomething("artDemand");
pM.DoSomething("productDemand");
}
}
}