迪米特法则|如何降低类间耦合


软件开发一直在推崇一个概念-低耦合、高内聚。 那什么样的代码设计才算得上低耦合、高内聚的代码。本文通过迪米特法则来讲解一下如何进行低耦合的代码设计。

迪米特法则也叫最小知识原则(Least Knowledge Principle),即一个类应该对自己需要耦合和调用的类保持最少的认识。也就是一个类对自己依赖的类知道的越少越好。因而迪米特法则应该遵循一下的要义

  1. 被依赖者,只应该暴露应该暴露的方法
  2. 依赖者,只依赖应该依赖的对象

一个案例

David Bock根据迪米特法则给出了一个超市购物的案例。
三个关键信息:消费者、钱包、收银员
定义了三个类,分别是Customer、Wallet、PaperBoy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Customer {
private String firstName;
private String lastName;
private Wallet myWallet;
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public Wallet getWallet(){
return myWallet;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Wallet {
private float value;
public float getTotalMoney() {
return value;
}
public void setTotalMoney(float newValue) {
value = newValue;
}
public void addMoney(float deposit) {
value += deposit;
}
public void subtractMoney(float debit) {
value -= debit;
}
}
1
2
3
4
5
6
7
8
9
10
public class Paperboy {
public void charge(Customer myCustomer, double payment) {
Wallet theWallet = myCustomer.getWallet();
if (theWallet.getTotalMoney() > payment) {
theWallet.subtractMoney(payment);
} else {
//money not enough
}
}
}

从这三个类可以看出, PaperBoy承担了大多数的功能实现。PaperBoy从消费者那里拿到了钱包,核点钱包的的金钱并自己从中拿去购物的费用。paperBoy既与Customer发生直接交互,又与Wallet发生间接交互,不符合最小知识原则(迪米特法则)。案例主要存在以下问题

  • Wallet暴露太多方法,其实Customer只要能够用钱包进行付钱就行了。所以这违反了迪米特法则的第一条(被依赖者,只暴露应该暴露的方法)
  • 让PaperBoy与Wallet直接交互是错误的行为,Wallet是Customer的私有财物,ParperBoy是无权过问Wallet的情况的, 所以从职责的角度上来看,这是不符合逻辑,违反了迪米特法则的第二条(依赖者,只依赖应该依赖的对象)

如何进行修改

  • PaperBoy不再与钱包发生直接关系,直接向customer要钱
  • 钱包只暴露付钱的方法给Customer。 方法暴露越多,后期需求变更的影响越大。
1
2
3
4
5
6
7
8
9
10
11
public class PaperBoy {
private Customer customer;

public PaperBoy(Customer customer){
this.customer = customer;
}

public void charge(float payment){
customer.pay(payment);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Customer {
private String firstName;
private String lastName;
private Wallet myWallet;

public Customer(String firstName, String lastName, Wallet myWallet) {
this.firstName = firstName;
this.lastName = lastName;
this.myWallet = myWallet;
}

public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}

public void pay(float payment){
myWallet.pay(payment);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Wallet {
private float value;
private float getTotalMoney() {
return value;
}
public void setTotalMoney(float newValue) {
value = newValue;
}
private void addMoney(float deposit) {
value += deposit;
}
private void subtractMoney(float debit) {
value -= debit;
}

public void pay(float payment){
if(getTotalMoney()>payment){
subtractMoney(payment);
}else {

}
}
}

迪米特法则核心观念— 类间解耦、弱耦合