title: 迪米特法则——合理的封装
date: 2016-10-22 18:55:36
tags:
- Java
- 设计模式
categories: 设计模式
背景
以服务员,客户,钱包为载体,模拟一个付款过程,阐述不恰当的封装行为。
说明合理封装的一般过程以及不合理封装所表现的一般形式,介绍迪米特法则相关的基本内容,遵循迪米特法则对问题代码进行重构。
看似没有问题的问题
先看一个简单代码,分别描述钱包、客户、服务员:
public class Wallet {
private double value;
public double getTotalMoney() {
return value;
}
public void setTotalMoney(double newValue) {
value = newValue;
}
public void addMoney(double deposit) {
value += deposit;
}
public void subtractMoney(double debit) {
value -= debit;
}
// 省略其它字段,方法
}
public class Customer {
private Wallet myWallet;
// 省略其它字段,方法
}
public class Paperboy {
private Customer myCustomer;
public void pay(double payment) {
Wallet theWallet = myCustomer.getWallet();
if (theWallet.getTotalMoney() > payment) {
theWallet.subtractMoney(payment);
} else {
//money not enough
}
}
}
一眼看过去,没毛病。几个基本的简单类在Paperboy的pay方法中实现了简单的业务逻辑,但翻译成“人类语言”就有点问题了:
业务的第一步造作:通过客户获取其钱包。
等等这样真的好吗?现实生活中仿佛讲不通啊,程序设计中其实违反了迪米特法则。
听到迪米特法则那一瞬间,我想到的是各种设计模式概念,尴尬的是就是想不起迪米特到底是个啥!
迪米特法则
迪米特法则(最小知识法则,强调专注性):
任何一个对象或者方法,它应该只能调用下列对象:
- 该对象本身和对象的属性
- 作为参数传进方法的对象
- 在方法内创建的对象
这下好像清晰多了,其实再通俗一点上面的代码就是违反了封装的原则。
合理的封装分为两步:
-
分辨职责
- 依据:数据与行为应该封装在一起(信息专家模式)
- 过程:职责操作哪些数据,数据在哪个(些)类,进而确定职责在哪个类
- 判别哪些是实现细节,哪些是可以公开的接口,以保证对细节的合理隐藏
不良封装造成的结果:Feature Envy(依恋情结)
不良封装可能的代码样式:
obj1.obj1_fun().obj2_fun();
类似链式的方法调用,但方法返回的是不同对象,这时候的代码很有可能是不良封装,违反迪米特法则了。
问题的解决
上面代码良好的封装示例:
public class Customer {
private Wallet myWallet;
public void pay(float payment) {
Wallet theWallet = myWallet;
if (theWallet.getTotalMoney() > payment) {
theWallet.subtractMoney(payment);
} else {
//money not enough
}
}
}
public class Paperboy {
private Customer myCustomer;
public void pay(float payment) {
myCustomer.pay(payment);
}
}
网友评论