Decoupling - Xinrea/Learn GitHub Wiki
步骤一 解决简单耦合
类型一
对于与对象状态无关的方法,可以直接将该方法本地化,解除耦合,例如:
class A {
B b;
...
aMethod() {
return b.add(1,2);
}
}
class B {
...
add(a,b) {
return a+b;
}
}
可见B.add()
方法只是完成了简单单一的功能,与类B的对象状态无关,因此可以将其本地化,直接代替原来的调用,以达到解耦的目的。解耦后如下所示:
class A {
...
aMethod() {
return 1+2;
}
}
类型二
调用位置在代码段末尾,而且改调用与自身状态无关,例如:
class A {
B b;
aMethod(){
dosomething();
b.inc();
}
}
class B {
static int m;
inc(){
m++;
}
}
class C{
A a;
cMethod(){
a.Method();
}
}
由于B.inc()
涉及到B的状态int m
,无法直接本地化到A中,但是该方法与A的状态无关,因此可以查找使用了aMethod
的地方,例如类C中的cMethod()
方法中调用了aMethod()
,我们可以将b.inc()
提到aMethod()
方法外,例如:
class A {
aMethod(){
dosomething();
}
}
class C{
A a;
B b;
cMethod(){
a.Method();
b.inc();
}
}
可见修改后,类A已经不依赖与类B。
步骤二 设计接口和工厂类
对于简单解耦无法完成的工作,就需要设计接口和工厂类来进行解耦了,这种方法简单粗暴,使用Java的反射机制来达到解耦的效果。 例如,有许多模块对模块A有引用,为了解决这种直接的耦合关系,需要为类A设计接口和工厂类。
查找类A中哪些方法被外部所使用,将其提取到IA接口类中,类A设置为implement IA; 实现一个类AFake,同样implement IA,这是当类A未定义时,默认使用的类。
接下来便是实现工厂类AFactory,结合Java的反射机制实现隔离,简单样例如下所示:
//IA.java
package com.test.decouple;
public interface IA {
boolean method();
}
//A.java
package com.test.decouple;
public class A implements IA {
public boolean method() {
return true;
}
}
//AFake.java
package com.test.decouple;
public class AFake implements IA {
public boolean method() {
return false;
}
}
//AFactory.java
package com.test.decouple;
public class AFactory {
private static final A = "com.test.decouple.A";
private static final AFake = "com.test.decouple.AFake";
public static IA getInstance() {
Class<IA> mClass = null;
IA mInst = null;
try {
mClass = (Class<IA>)Class.forName(A);
} catch (ClassNotFoundException e) {
try {
mClass = (Class<IA>)Class.forName(AFake);
} catch (ClassNotFoundException e2) {
e2.printStackTrace();
}
}
mInst = mClass.newInstance();
return mInst;
}
}
工厂类AFactory中,使用反射来使用类A,当查找不到类A时,转而使用类AFake,确保不会出错。这样进行处理后,工厂类AFactory会根据类A存在与否来选择实例化的方式。替换掉所有使用了method()
方法的地方后,外部就不再依赖于类A了,这样就达到了单方向完全解耦的效果。