赞
踩
我们写代码时经常希望能应用面向对象的一些原则,希望我们的代码能合适的封装、松耦合、健壮和复用,也希望我们的应用可扩展和可维护。通常这些原则比较抽象难以直接应用,都是根据经验和直觉来应用他们。现在有一个法则可以帮我们做选择,这个法则是:迪米特法则(The Law of Demeter),简称LOD。它是面向对象编程中一个比较简单的一个法则,使用它能保障我们代码和应用满足上面提到一些抽象原则。
定义是:只与你的直接朋友交谈。定义是不是很简单,但是在面向对象编程中它意味着什么呢?在编程中,与一个对象交谈意思是调用一个对象的方法。根据迪米特法则,对象O的方法M 应该只能调用下面的方法:
关于直接朋友有个图例,如下:
法则告诉我们不需要知道我们接收对象的内部实现细节,我们只需要关心方法的业务逻辑和一些其他对象被告知的信息,不需要主动询问或探索其他对象的内部实现细节。来看一个例子,我们有一个包含员工对象的集合,想从中获取员工的街区信息,代码如下:
class BasicExample {
public String getStreetName(Employee employee) {
Address address = employee.getAddress();
return address.getStreetName();
}
}
这段代码,我们访问了 employee 对象的 address 字段,并从中获取 street 信息,这违反了迪米特法则。因为我们不需要知道 emplyee 对象有 address 字段,只需要从 employee 对象中获取信息而不用关心它是如何存储的,address 对象不是当前对象的直接朋友。现在修改上面的代码来满足迪米特原则:
class Employee {
private Address address;
public String getStreetName() {
return address.getStreetName();
}
}
class BasicExample {
public String getStreetName(Employee emplyee) {
employee.getStreetName();
}
}
上面这段代码,我们只需要从employee 对象获取 adress 信息,如果将来employee 对象中改变了address 信息的存储也不会影响我们获取信息的代码。
我们经常会写出如下代码,o.getA().getB().getC() ,如果这些getter 方法返回不同的字段,就违反了 LOD 原则,如果一个直接朋友对象返回另外一个对象,我们不应该再调用这个另外的对象的方法。但是怎么写链式调用,才符合 LOD 原则呢,原则有一点说明是可以调用在方法内部创建的变量,例如:
class C {
public M createM() {
return new M();
}
}
c.createM().getO() 如此调用符合LOD 法则。在方法内部新创建一个对象,此对象不被其他对象引用,调用此对象的方法所造成的影响也是局部的。
有个创建披萨的构造器,如下:
public static class PizzaBuilder { private Integer size; private String topping; public Pizza build() { Pizza pizza = new Pizza(); pizza.size = this.size; pizza.topping = this.topping; return pizza; } public PizzaBuilder setSize(Integer size) { this.size = size; return this; } public PizzaBuilder setTopping(String topping) { this.topping = topping; return this; } } public class Test { public Pizza createPizza() { PizzaBuilder pizzaBuilder = new PizzaBuilder(); Pizza pizza = pizzaBuilder.setSize(30).setTopping(“Cheese”).build(); return pizza; } }
从上代码可以看出,pizza 对象是build 方法内创建的,以为着我们可以调用它的方法,因此,builder pattern 看起来是违反LOD 原则,其实是不违反的,builder 模式的本质是方法链式调用。
例外
当我们的方法接收一些数据结构当参数时,例如集合,我们可以调用集合的方法并迭代它里面的对象,此操作符合LOD 法则,但是如果我们调用集合对象里的方法,此时违反LOD 法则吗?例如下代码:
public void m(List < Order > orders) {
for (int i = 0; i < orders.size(); i++) { //可接受
Order order = orders.get(i); // 可接受
order.buy(); // 可接受吗?
}
}
List 本身是一个对象,我们调用它自身 size() 和 get() 方法,肯定符合法则,但是 order.buy() 呢? 从严格定义来说,违反了法则,但是我们把包含多个对象的集合作为参数传递,也可以把集合里的对象当做直接朋友对象,在这里是可以接受的。当然也可以把这个集合迁移到一个对象中去,但这往往没必要。
迪米特法则不是面向对象编程所需要的银弹,但是我们编程时遵守它可以带来很多好处,可以保障我们的代码结构清晰、灵活、更易维护。
在我们日常工作中,经常会接手维护一些老项目,如果之前的代码设计耦合度很高,阅读性较差,维护起来你是不是感觉很痛苦,总有感觉牵一发动全身。如果当时的代码符合迪米特法则,写出的代码基本上是松耦合、高内聚、易维护。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。