一、局部化修改——目标是减少由某个变更直接影响的模块的数量;
1、预期期望的变更(expected changes ):
确保canVote() 方法返回true或者false, 同时你也能写一个测试用来验证这个方法抛出的IllegalArgumentException异常。
public class Student { public boolean canVote(int age) { if (i<=0) throw new IllegalArgumentException("age should be +ve"); if (i<18) return false; else return true; } }
Guava类库中提供了一个作参数检查的工具类--Preconditions类,也许这种方法能够更好的检查这样的参数,不过这个例子也能够检查
2、维持语义一致性(semantic coherence ):
3、泛化模块(Generalize the module ):
4、限制选择参数(Limit possible options ):
二、防止连锁反应——目标是限制对局部化的模块的修改,以防止对某个模块的修改间接地影响到其他模块;
尽量维持现有接口或类的名字等不变,把要改动的模块尽量降到最低。推迟绑定时间在我的系统中还没有体现出来。
维持语义的一致性是保证模块中不同责任之间可以协同工作,不要太多的依赖于其他的模块。
1、信息隐藏(Hide information ):
2、维持现有接口(Maintain existing interfaces ):
3、限制通信路径(Restrict communication paths ):
4、使用仲裁者(Use an intermediary ):
采用迪米特法则可以有效防止连锁反应:
例子:
在美国电影《教父》中,教父如果为了除掉对手,会亲自动手吗?肯定不,教父会安排手下人处理。教父这样位高权重的人,会直接跟杀手安排任务吗?一般不会,他会跟手下的心腹说明,然后由手下人去执行。
这样一来,我们看看,先看看三个普通角色,被杀的人Person,杀手Killer,心腹CoreMember,如下:
/** * 某个人 * @author ljtyzhr * */ public class Person{ public String name; } /** * 杀手 * @author ljtyzhr * */ public class Killer{ public void kill(Person someone){ System.out.println(someone.name+"被杀死了"); } } /** * 教父身边的核心人员 * * @author ljtyzhr * */ public class CoreMember{ private Killer killer; }
事实上,核心人员直接与杀手打交道,教父只会与心腹打交道,如此,关系应该如下:
/** * 教父身边的核心人员 * * @author ljtyzhr * */ public class CoreMember{ private Killer killer; public void kill(Person someone){ killer.kill(someone); } }
家父持有对核心人员的引用,如下:
/** * 教父 * @author ljtyzhr * */ public class GodFather{ CoreMember coremember; public void kill(Person someone){ Killer killer = new Killer(); killer.kill(someone); } }
实现区块的隔离,使得模块之间具有独立性
三、延迟绑定时间——目标是控制部署时间并允许非开发人员进行修改。
1、运行时注册(Runtime registration):
2、配置文件(Configuration files):
3、多态(Polymorphism):
4、组件更换(Component replacement ) :
5、遵守已定义的协议(Adherence to defined protocols) :
延时0.5秒后发送一个网络请求,首先想到了handler,结果出现这么一个错误,解决方案很简单,就是在线程里调用Looper.prepare(),然后调用Looper.loop()就可以了
private void sendMessageToClient(final StringBuilder s){ new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } sendToClient.sendDataToClient(s,clientSocketAddress);//网络请求必须在子线程 } }).start(); }