> 文章列表 > 《重构》:移除中间人(Remove Middle Man)/ 偶尔有用的迪米特建议

《重构》:移除中间人(Remove Middle Man)/ 偶尔有用的迪米特建议

今天我看到一篇关于软件重构的文章,讲的是“移除中间人”和“隐藏委托关系”这两个技巧。说实话,一开始我还以为它们是对立的,结果发现它们其实是好朋友,可以在不同情况下互帮互助。比如,当你有一个复杂系统的“洋葱头”结构,想让代码更易读,就可以让隐藏委托关系先上场,把复杂度封装起来。但是,如果发现洋葱头层数太多,直接用移除中间人来简化一下,是不是更爽?

比如,假设你有一个订单系统,里面有个订单对象,订单里有个顾客对象,顾客里又有地址对象。要获取地址信息,隐藏委托关系就是让顾客给你一个“get地址”的按钮,而移除中间人则是直接让你从顾客那里拿到地址,不用按按钮。这样,代码更简洁明了。

整体而言,这两个技巧都是为了降低代码的耦合性,但一个侧重于封装,另一个侧重于简化调用链。选择哪个,要看你“洋葱头”里的层数有多少啦!

《重构》:移除中间人(Remove Middle Man)/ 偶尔有用的迪米特建议

首先明确,Remove middle man 和 hide delegate 这两种重构技巧并不是对立面。

隐藏委托关系和移除中间人这两种重构技巧并不是相对立的,它们可以互相结合使用。

在某些情况下,使用隐藏委托关系能够将复杂度封装在一个类中,并提供一个更加简单的接口客户端,从而降低耦合性。

但是,在某些复杂的对象之间如果存在多层嵌套的情况,使用隐藏委托关系可能会导致代码的可读性变差,因为需要在多个类之间进行上下文切换,看起来会比较繁琐。这时候,就可以考虑使用移除中间人来减少嵌套关系、简化调用链。

隐藏委托关系(Hide Delegate)和移除中间人(Remove Middle Man)这两个重构技巧有相似之处,都是为了降低代码的耦合性。但是它们侧重的点不同。

隐藏委托关系指的是在一个对象中封装其所使用的另一个对象,并提供一个简单的接口来访问该对象的方法,从而隐藏掉客户端与被委托对象之间的直接关系,以达到降低耦合度的目的。

而移除中间人则是指减少客户端代码对于多层嵌套结构中的中间对象的依赖关系,通过直接访问最终的对象,将中间对象从调用链中移除,从而达到简化代码、提高可读性和可维护性的目的。

举个例子:

假设我们有一个订单类 Order 中含有顾客 Customer 对象,在顾客类中又嵌套了 Address 类,现在需要获取订单中顾客的地址信息。如果使用隐藏委托关系技巧,则可能会在 Customer 类中添加一个 getAddress() 方法,然后在 Order 类中直接使用 customer.getAddress() 方法来获取顾客的地址信息,这样可以隐藏掉 Order 类与 Address 类之间的直接关系。

如果使用移除中间人的技巧,可能会直接在 Order 类中通过 customer.address 来获取顾客地址信息,这样就不必在 Customer 类中添加额外的方法。

因此,这两个重构技巧可以结合使用,但是根据具体场景和代码结构的不同,需要选择合适的技巧来达到降低代码耦合度的目的。

JS代码举例子:


class Department {constructor(manager) {this.manager = manager;}getManager() {return this.manager;}
}class Manager {constructor(name) {this.name = name;}getName() {return this.name;}getDepartmentName() {return this.department.getName();}
}class Employee {constructor(name, manager) {this.name = name;this.manager = manager;}getName() {return this.name;}getManager() {return this.manager;}getManagerName() {return this.manager.getName();}getManagerDepartmentName() {return this.manager.getDepartmentName();}
}

在这个示例中,我们可以看到 Manager 类扮演了一个“中间人”的角色,它将 Employee 对象委托给 Department 对象来获取部门名称。

使用移除中间人重构后,代码如下所示:

class Department {constructor(name) {this.name = name;}getName() {return this.name;}
}class Employee {constructor(name, department) {this.name = name;this.department = department;}getName() {return this.name;}getDepartmentName() {return this.department.getName();}
}

在这个示例中,我们已经成功移除了 Manager 类,将 Employee 和 Department 直接联系起来。这样可以减少代码的复杂性和不必要的耦合性,从而提高代码的可读性和可维护性。

注:暂时工作中还没见过这种耦合性代码,也有可能是我没有注意到。。