我理解的解耦

1.静态解耦:
先解释下我理解的静态耦合,指的是编译期依赖关系已经确定,在运行时环境中,代码间的依赖关系不能改变。例如,我们在开发中经常会说的“把代码写死了”。静态是相对动态的、运行时的、可配置的和插件式的。
那么在静态环境中,如何解耦?主要是依赖接口。下面举两个小例子简单说明下:
EX1: 假设一个人不知道接口的意义,那么他写出两个类的依赖关系一般如下:

public class ClassA {
public void invoke() {
[color=blue]ClassB b = new ClassB();
b.action();[/color] //do some other things
}
}

public class ClassB {
public void action() {
//do something
}
}

我们常常说的“耦合”,我认为一个重要的因素就是环境的变,如果没有变化的环境,那么多么的“耦合”也是无所谓的;假如现在变化来了,ClassA中的invoke()方法不符合现在的需求了,而且需要改变的部分恰好是invoke()中的前两行,也正是和ClassB耦合的那部分,而ClassB的action方法还在别的代码有调用。现在如果更改,则必须修改invoke()的前两行代码。这个是面向对象中非常忌讳的。所谓代码应该[color=red]对扩展开放,对修改封闭[/color],那么我们用“面向接口编程”的思想对他进行一下改造吧。

public class ClassA {
public void invoke() {
Interface i = Factory.newInstance().produce(1);
i.action();
}
}
public class Factory {
private static Factory f = new Factory();

public static Factory newInstance() {
return f;
}

public Interface produce(int k) {
if(k == 0) {
return new Imp1();//接口的实现类1
} else if (k == 1){
return new Imp2();//接口的实现类2
}//other implements

return new DefautImpl();
}
}

现在的情况稍好一点了,至少我们把变化集中管理在了一个工厂类中,但是,如果有变化,我们还是要深入代码去修改这个工厂类,依赖关系仍旧局限于编译期;
难道没有解决办法了吗?当然有,那就是我理解的动态解耦。

2.动态解耦
所谓动态是对象之间的依赖关系不依赖于编译期,运行时动态确定。动态解耦与插件式,可配置具有某种意思的巧合。套用某句话,正是因为有了动态解耦技术,代码间的依赖关系才真正解脱了。
动态解耦所用的技术主要是反射机制并结合配置文件。下面是一个例子,仅仅演示什么是动态的(很粗糙的。。)


public class Main {

/**
* @param args
*/
public static void main(String[] args) {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

while(true) {
String instruction = null;
try {
instruction = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}

if("exit".equalsIgnoreCase(instruction)) {
break;
}

if("invoke".equalsIgnoreCase(instruction)) {
//一个类和被调用类直接耦合在一起
Interface inter = loadFromCfgFile();
if(inter == null) continue;

inter.say("just say");
}
}

}

private static Interface loadFromCfgFile() {
InputStream in = MainClass.class.getResourceAsStream("test.properties");
Properties p = new Properties();
try {
p.load(in);
} catch (IOException e) {
e.printStackTrace();
return null;
}

String className = p.getProperty("class");
System.out.println("class name loaded from config file is: " + className);

Object object = loadClassAccordingClassName(className);
if(object == null) return null;


return (Interface) object;
}

private static Object loadClassAccordingClassName(String className) {
Class<?> clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
System.out.println("can not find the class.");
}
if(clazz == null) return null;

Object object = null;
try {
object = clazz.newInstance();
} catch (InstantiationException e) {
System.out.println("can not instance the class.");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("can not instance the class....");
e.printStackTrace();
}
return object;
}

}


实现类代码:

public class ImplementClass implements Interface{

public void say(String str) {
System.out.println("say " + str);
//System.out.println("added later.");//

}

}


配置文件代码:

class=ImplementClass


你可以简单的修改ImplementClass.java的代码,加上注释掉的语句,编译后,就会发现输出和以前不同了。
如上所示,代码间的依赖关系,从源代码中移动到了配置文件中,并利用反射技术来动态确定其依赖关系;好处就是依赖集中管理、符合开放封闭原则;
对配置文件的修改产生的变化,还有一种更优雅的方式,可以启动一个守护线程对其进行定期检查,如变化,可重新加载并实例化,这个以后再续;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值