引言:
自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。
问题由来:
类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
解决方案:
尽量降低类与类之间的耦合。
定义:
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
例子:
有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工ID。
先来看一下违反迪米特法则的设计:
//总公司员工
class Employee
{
private String id;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
}
//分公司员工
class SubEmployee
{
private String id;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
}
class SubCompanyManager
{
public List<SubEmployee> getAllEmployee()
{
List<SubEmployee> list = new ArrayList<SubEmployee>();
for(int i=0; i<100; i++)
{
SubEmployee emp = new SubEmployee();
//为分公司人员按顺序分配一个ID
emp.setId("分公司"+i);
list.add(emp);
}
return list;
}
}
class CompanyManager
{
public List<Employee> getAllEmployee()
{
List<Employee> list = new ArrayList<Employee>();
for(int i=0; i<30; i++)
{
Employee emp = new Employee();
//为总公司人员按顺序分配一个ID
emp.setId("总公司"+i);
list.add(emp);
}
return list;
}
public void printAllEmployee(SubCompanyManager sub)
{
List<SubEmployee> list1 = sub.getAllEmployee();
for(SubEmployee e:list1)
{
System.out.println(e.getId());
}
List<Employee> list2 = this.getAllEmployee();
for(Employee e:list2)
{
System.out.println(e.getId());
}
}
}
public class Client
{
public static void main(String[] args)
{
CompanyManager e = new CompanyManager();
e.printAllEmployee(new SubCompanyManager());
}
}
现在这个设计的主要问题出在CompanyManager中,根据迪米特法则,只与直接的朋友发生通信,而SubEmployee类并不是CompanyManager类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲总公司只与他的分公司耦合就行了,与分公司的员工并没有任何联系,这样设计显然是增加了不必要的耦合。按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合。修改后的代码如下:
class SubCompanyManager
{
public List<SubEmployee> getAllEmployee()
{
List<SubEmployee> list = new ArrayList<SubEmployee>();
for(int i=0; i<100; i++)
{
SubEmployee emp = new SubEmployee();
//为分公司人员按顺序分配一个ID
emp.setId("分公司"+i);
list.add(emp);
}
return list;
}
public void printEmployee()
{
List<SubEmployee> list = this.getAllEmployee();
for(SubEmployee e:list)
{
System.out.println(e.getId());
}
}
}
class CompanyManager
{
public List<Employee> getAllEmployee()
{
List<Employee> list = new ArrayList<Employee>();
for(int i=0; i<30; i++)
{
Employee emp = new Employee();
//为总公司人员按顺序分配一个ID
emp.setId("总公司"+i);
list.add(emp);
}
return list;
}
public void printAllEmployee(SubCompanyManager sub)
{
sub.printEmployee();
List<Employee> list2 = this.getAllEmployee();
for(Employee e:list2)
{
System.out.println(e.getId());
}
}
}
修改后,为分公司增加了打印人员ID的方法,总公司直接调用来打印,从而避免了与分公司的员工发生耦合。