解耦是为了方便拓展与维护,你一个HelloWorld解个什么耦。

解耦概念

解耦与耦合对应,我们首先要明白什么是耦合。

耦合

耦合表示了两个对象间的相关关系程度,也就可以叫耦合度(对于不同的对象,耦合度的概念也有所不同)。就像是钥匙与锁一样,只有完整匹配上锁纹的钥匙才可以开锁,这种就是高耦合度。

高耦合强调了唯一关系,也就是越高耦合的钥匙与锁套件,越安全。但是换做代码中,也就是你只能用这把钥匙(调用逻辑)来开启需要的锁(调用目标)。举个例子:

SaySomething.java
1
2
3
4
5
6
7
8
public class SaySomething {
public void sayHi() {
System.out.println("hi");
}
public void sayHello() {
System.out.println("hello");
}
}

我们现在有一个SaySomething的类,用来输出打招呼的话,其中我们定义了两个方法,一个是sayHi,一个是sayHello,这样我们就可以通过这个类的实例来进行两种方式的打招呼。比如:

1
2
SaySomething saySomething = new SaySomething();
saySomething.sayHi();

此时如果没有其他的打招呼方式的话,那我们的代码就到此为止了。但是如果我们此时想要增加一种打招呼的方式,比如输出你好,那我们该怎么办呢?

解耦

在以上的例子中,你肯定第一时间想到了可以将我们的想要输出的对象换成参数传入,比如这样:

SaySomething.java
1
2
3
4
5
6
public class SaySomething {

public void say(Object hi) {
System.out.println(hi);
}
}

那我们的调用可以这样进行:

1
2
SaySomething saySomething = new SaySomething();
saySomething.say("你好");

没错,这也是我们解耦的一种方式:配置化

配置化

我们将我们会用到可变参数进行配置化,将这些配置封装成入参传入方法,由方法来处理配置。

换句话说,我们提供了一套配置,由调用方法来理解我们的配置,并输出我们想要的内容。

这样似乎是很方便了,但是很明显可以看出,如果我们想要输出一个User类的信息,如果直接放入一个User对象会怎样呢?

1
2
SaySomething saySomething = new SaySomething();
saySomething.say(new User());

输出了对象hash值,很显然这不是我们想要的。当然,我们可以在重写User.toString()方法来输出我们想要的值,但是这破坏了我们的类,侵入性太强了。我们也可以将调用写成saySomething.say(new User().getName());,但是这并不符合我们对这个方法的期待。

所以我们又想了一个办法,通过接口重写的方式来适配不同的类,此时我们将SaySomething变为一个接口:

1
2
3
4
public interface SaySomething<T> {

void say(T hi);
}

然后我们给User一个适配实现:

1
2
3
4
5
6
7
public class SayUser implements SaySomething<User> {

@Override
public void say(User hi) {
System.out.println(hi.getName());
}
}

此时我们就可以这样来调用代码:

1
2
SaySomething<User> saySomething = new SayUser();
saySomething.say(new User());

对于其他的对象,我们就增加对应的实现类就可以了,这种方式就是:接口规范

接口规范

将我们需要使用的方法进行接口化,也就是与方法提供方协定一个调用规范,双方通过这个调用规范进行调用和解析。

接口类也只是接口规范的其中一个方式,像是网络服务中的接口API也是接口规范的一种。

当然,我们在使用时也发现了一个问题:我们对于每一个需要处理的对象都需要构建对应的实现类,这种方式很繁琐,并且不通用。

所以我们可以转换一下思路,我们不改变SaySomething代码,转而改变其中的调用方法:

1
2
3
4
5
6
7
8
9
10
public static class SaySomething {

public void say(Sayable sayable) {
System.out.println(sayable.print());
}
}

public interface Sayable {
String print();
}

也就是说我们规定,只有实现了Sayable接口的类实例我们才允许使用这个方法。这样,我们只需要让User类去实现这个接口就可以了。虽然这与重写toString()方法都是在侵入调用方的代码,但是不同于重写方法,实现类的方式并不会影响原有的类逻辑。

这里我们就是用的另一种接口规范:参数规范

参数规范

参数规范的应用场景很广,因为它可以有效减低非预期结果的出现概率。比如我们定义的Sayable接口,就将格式处理转交给了调用方,就能让调用方来确定输出格式。

到此我们发现,


本站总访问量