六大设计原则
定义
一个对象应该对其他对象保持最少的了解
迪米特法则又叫最少知道原则,只与朋友说话,不要与陌生人说话。对类而言,哪些是朋友类呢?出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。也就是说,方法体内的局部变量最好不是陌生类。
场景
我们设计一个场景,客户的空调坏了,联系商家叫维修师傅上门维修空调:
// 工具类
public class Tool {
public String getName() {
return "扳手";
}
}
// 维修师傅
public class Worker {
public void doWork(Tool tool) {
System.out.println("维修师傅用" + tool.getName() + "在维修空调");
}
}
// 商家
public class Business {
private Worker worker;
public Business() {
worker = new Worker();
}
public void command() {
Tool tool = new Tool();
worker.doWork(tool);
}
}
// 客户
public class Client {
public static void main(String[] args) {
Business business = new Business();
business.command();
}
}
我们重点分析商家类Business,它的直接朋友类是维修师傅类Worker(出现在成员变量中),可是command方法内却出现结果陌生的工具类Tool。商家类Business其实并不需要知道工具类Tool的存在,他只与维修师傅类Worker打交道就行,至于师傅用什么工具,他不care的。
所以,我们需要修改一下:
// 维修师傅
public class Worker {
public void doWork() {
Tool tool = new Tool();
System.out.println("维修师傅用" + tool.getName() + "在维修空调");
}
}
// 商家
public class Business {
private Worker worker;
public Business() {
worker = new Worker();
}
public void command() {
worker.doWork();
}
}
这样修改之后,商家类Business就不再依赖工具类Tool了,因为根本不需要知道。
但是也不能和朋友类过于“亲密”,知道就好,还是延续上面的例子说明。维修空调可能需要很多工具,除了扳手,还有螺丝刀,清洁工具等。
// 工具接口
public interface Tool {
String getName();
}
// 扳手工具类
public class BanShou implements Tool {
return "扳手";
}
// 螺丝刀工具类
public class LuoSiDao implements Tool {
return "螺丝刀";
}
// 清洁工具工具类
public class QingJieTool implements Tool {
return "清洁工具";
}
// 维修师傅
public class Worker {
// 用扳手修空调
public boolean doWork1() {
BanShou tool = new BanShou();
System.out.println("维修师傅用" + tool.getName() + "在维修空调,没修好");
return false;
}
// 用螺丝刀修空调
public boolean doWork2() {
LuoSiDao tool = new LuoSiDao();
System.out.println("维修师傅用" + tool.getName() + "在维修空调,没修好");
return false;
}
// 用清洁工具修空调
public boolean doWork3() {
QingJieTool tool = new QingJieTool();
System.out.println("维修师傅用" + tool.getName() + "在维修空调,修好了");
return false;
}
}
// 商家
public class Business {
private Worker worker;
public Business() {
worker = new Worker();
}
public void command() {
if (worker.doWork1()) {
System.out.println("维修师傅使用扳手修好了空调");
} else if (worker.doWork2()) {
System.out.println("维修师傅使用螺丝刀修好了空调");
} else if (worker.doWork3()) {
System.out.println("维修师傅使用清洁工具修好了空调");
} else {
System.out.println("维修师傅修不好空调了");
}
}
}
例子中,商家类Business的确只与朋友类Worker说话,但是不觉得商家类Business知道管太多了吗?还要“指挥”维修师傅类Worker怎么去修。这是因为维修师傅类Worker“告诉”商家类Business太多“秘密”了,也就是公布太多方法了!既然知道原因,那就把方法私有化,自己知道就行:
// 维修师傅
public class Worker {
// 用扳手修空调
private boolean doWork1() {
BanShou tool = new BanShou();
System.out.println("维修师傅用" + tool.getName() + "在维修空调,没修好");
return false;
}
// 用螺丝刀修空调
private boolean doWork2() {
LuoSiDao tool = new LuoSiDao();
System.out.println("维修师傅用" + tool.getName() + "在维修空调,没修好");
return false;
}
// 用清洁工具修空调
private boolean doWork3() {
QingJieTool tool = new QingJieTool();
System.out.println("维修师傅用" + tool.getName() + "在维修空调,修好了");
return false;
}
// 修空调
public void doWork() {
if (doWork1()) {
System.out.println("维修师傅使用扳手修好了空调");
} else if (doWork2()) {
System.out.println("维修师傅使用螺丝刀修好了空调");
} else if (doWork3()) {
System.out.println("维修师傅使用清洁工具修好了空调");
} else {
System.out.println("维修师傅修不好空调了");
}
}
}
// 商家
public class Business {
private Worker worker;
public Business() {
worker = new Worker();
}
public void command() {
worker.doWork();
}
}
维修师傅值提供一个方法,就是维修空调,至于怎么维修,那就是维修师傅自己的事了!这样,即使维修师傅更换维修方式,也和商家无关,商家类Business不用做任何修改!
小结
综上,最少知道原则有2个核心思想:
- 尽量不要和陌生类产生依赖关系;
- 尽量不要知道朋友类太多细节;
总得来说,迪米特法则的主要目的是减少类没必要的依赖,降低类之间的耦合度。