参考文章:
https://www.jianshu.com/p/14589fb6978e
https://www.cnblogs.com/shangxiaofei/p/5071211.html
使用参考文章里的例子来说事儿,我想实现电脑的关机功能,关机有几个步骤:保存系统当前正在执行的任务,关闭服务程序,关闭显示器,关闭电源;
最简单的实现:
public class Computer {
public void saveCurrentTask()
{
System.out.println("save current task successfully!");
}
public void closeServices()
{
System.out.println("close services successfully!");
}
public void closeScreen()
{
System.out.println("close screen successfully!");
}
public void closePower()
{
System.out.println("colse power successfully!");
}
}
应用场景:
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Computer computer = new Computer();
computer.saveCurrentTask();
computer.closeServices();
computer.closeScreen();
computer.closePower();
}
}
这时候问题就来了,Computer暴露出来很多接口供外部使用,如果提供给其他人员实现应用场景,我估计他会一脸懵逼,他不确定应该调用哪些函数去实现关机,更不知道这些函数的调用次序,就算你写接口文档估计别人都能看吐了。
再来一个例子,大学的选修课你们上过吗?反正我是不上,反正老师也不点名。而班主任会在学期快要结束的时候和班长要所有学生选修课的作业。于是,所有选择同一选修课的学生的作业相似度极高,不同的地方还是学委的功劳。现在我们来模拟一下老师要作业的场景:
public class StudentA {
//学生A选修的是语文
public void getCollegeChineseWork()
{
System.out.println("关关雎鸠,在河之洲...");
}
}
public class StudentB {
//学生A选修的是数学
public void getCollegeMathematicsWork()
{
System.out.println("八楼不算高,做的事平抛...");
}
}
//班长
public class Monitor {
private StudentA a;
private StudentB b;
public Monitor()
{
a = new StudentA();
b = new StudentB();
}
public StudentA getStudentA() {
return a;
}
public StudentB getStudentB() {
return b;
}
}
public class Teacher {
private Monitor monitor;
public Teacher() {
// TODO Auto-generated constructor stub
monitor = new Monitor();
}
//期末考试
public void finalExam()
{
monitor.getStudentA().getCollegeChineseWork();
monitor.getStudentB().getCollegeMathematicsWork();
}
}
public class Client {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.finalExam();
}
}
从上面的结构能看出来,班长和下面的学生是好朋友(private),班主任和班长关系也很好(private),现在班主任让班长把这两个学生请到办公室来检查作业,没有问题。但是反过来想想班主任和学生关系就好吗(朋友的朋友)?由于两者关系不一定好,导致下学期两个学生报的选修课变化了而老师不知道,这个时候finalExam()函数就要被动的去改变。而这个变化本应该班长就可以处理而不需要老师知道的。
以上两个栗子都违反了迪米特原则,第一个栗子中类的元素过渡的开放导致调用者与其耦合变大,第二个栗子中类在函数中依赖了非必要的类导致其与其他类的耦合变大。
迪米特原则:最少知道原则。
对于一个类,怎么样才是最少知道?
一、对自身行为及属性做最严格的权限设置,使其可以被简单明了的调用。
二、尽量减少对其他类的依赖,怎么减少呢?
1、only talk to your immedate friends,翻译过来是:之和直接朋友交互,所谓的直接朋友通常以成员变量,方法的参数和返回值的形式出现。尽量避免其他自定义类以局部变量的形式出现在类中,否则会不知不觉增加潜在的耦合;在类中尽量避免使用朋友的朋友,类似:m_frienda.getClassA().func(),这样也会增加与其他类的耦合。
2、对于真正的朋友类,也可以以抽象的形式使用,这也在一定程度上减少了与其他类的耦合。
我们来看看以上两个栗子怎么在迪米特原则下实现:
1、关闭电脑:
public class Computer {
private void saveCurrentTask()
{
System.out.println("save current task successfully!");
}
private void closeServices()
{
System.out.println("close services successfully!");
}
private void closeScreen()
{
System.out.println("close screen successfully!");
}
private void closePower()
{
System.out.println("colse power successfully!");
}
public void shutdown()
{
saveCurrentTask();
closeServices();
closeScreen();
closePower();
}
}
应用场景:
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Computer computer = new Computer();
computer.shutdown();
}
}
2、班主任检查作业:
public class StudentA {
//学生A选修的是语文
public void getCollegeChineseWork()
{
System.out.println("关关雎鸠,在河之洲...");
}
}
public class StudentB {
//学生A选修的是数学
public void getCollegeMathematicsWork()
{
System.out.println("八楼不算高,做的事平抛...");
}
}
//班长
public class Monitor {
private StudentA a;
private StudentB b;
public Monitor()
{
a = new StudentA();
b = new StudentB();
}
//期末考试
public void finalExam()
{
a.getCollegeChineseWork();
b.getCollegeMathematicsWork();
}
}
public class Teacher {
private Monitor monitor;
public Teacher() {
// TODO Auto-generated constructor stub
monitor = new Monitor();
}
//期末考试
public void finalExam()
{
monitor.finalExam();
}
}
public class Client {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.finalExam();
}
}