例子摘自 Thingking in java8第10章接口之完全解耦一节.
https://lingcoder.github.io/OnJava8/#/book/10-Interfaces?id=%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%80%a6
刚开始Processor是个父类,
class Processor {
public String name() {
return getClass().getSimpleName();
}
public Object process(Object input) {
return input;
}
}
下面一堆子类继承他,然后将声明的父类传到Applicator类的方法中.
public class Applicator {
public static void apply(Processor p, Object s) {
System.out.println("Using Processor " + p.name());
System.out.println(p.process(s));
}
}
这样做Processor就只能处理某一种类型的对象.没有解耦.
现在有类似方法的类Filter出现了,想要复用Applicator类代码.但是因为apply方法接收的是Processor类所以没法复用.
class Filter {
public String name() {
return getClass().getSimpleName();
}
public Waveform process(Waveform input) {
return input;
}
}
如果Processor是一个接口,apply方法接收一个接口参数,那么就不会跟具体的类绑定,实现了解耦.
interface Processor {
default String name() {
return getClass().getSimpleName();
}
Object process(Object input);
}
Applicator改写成接收接口参数的形式:
Applicator还是个类,它里面保有固定的具体的方法代码.
虽然apply方法里参数是接口形式的,但实际要传实现类进去
class Applicator {
//现在Processor是接口
public static void apply(Processor p, Object s) {
System.out.println("Using Processor " + p.name());
System.out.println(p.process(s));
}
}
现在的Processor是一个抽象的笼统的”处理器”角色,
可以根据不同任务创建不同的,特定方向的”子处理器”角色.
子类型接口继承父类型接口(接口不能继承类,否则会获得父类的构造方法,而接口只允许有静态变量,默认方法或抽象方法)
interface StringProcessor extends Processor {
@Override
String process(Object input); // [1]
String S = "If she weighs the same as a duck, she's made of wood"; // [2]
}
然后根据子接口创建更具体的实现类Upcase来处理任务.
class Upcase implements StringProcessor {
// 返回协变类型
@Override
public String process(Object input) {
return ((String) input).toUpperCase();
}
}
现在Applicator可以工作了:
public class test{
static void main(String[] args) { // [3]
Applicator.apply(new Upcase(), S);
Applicator.apply(new Downcase(), S);
Applicator.apply(new Splitter(), S);
}
}
但是现实情况是很多类是已有的或别人创建的,只能拿来用但是不能修改.
所以上面的情况可以再改成适配器设计模式.适配器允许代码接受已有的接口产生需要的接口.
这里有一个Filter类的子类:
public class HighPass extends Filter {
double cutoff;
public HighPass(double cutoff) {
this.cutoff = cutoff;
}
@Override
public Waveform process(Waveform input) {
return input;
}
}
改成下面这个样子:
public class FilterProcessor {
public static void main(String[] args) {
Waveform w = new Waveform();
Applicator.apply(new FilterAdapter(new LowPass(1.0)), w);
Applicator.apply(new FilterAdapter(new HighPass(2.0)), w);
Applicator.apply(new FilterAdapter(new BandPass(3.0, 4.0)), w);
}
}
public class LowPass extends Filter {
double cutoff;
public LowPass(double cutoff) {
this.cutoff = cutoff;
}
@Override
public Waveform process(Waveform input) {
return input; // Dummy processing 哑处理
}
}
在StringProcessor的例子里,Upcase类里的方法是String自带的.无需指定其他对象.
但是Waveform的例子里,处理波的对象是Filter,需要从外面引入.
怎么调和这种差异呢?
apply方法的参数已经定义好了,一个处理者(接口),一个被处理者.
解决办法是:对于waveform例子,引入适配器adapter这一对象去引入Filter.适配器实现了接口.可以满足apply的参数要求.
简单来说,stringProcessor的例子里,只需要2个参数,处理者和被处理对象,调的是对象的方法.
wave的例子里调的是处理者的方法.
apply方法的第一个参数就有了不一致的情形.也就是Processor里的process方法是有区别的.
stringProcessor例子里的process方法只要被处理着本身一个参数,
wave例子里需要引入处理者,
但是process方法是固定的.不能从入参去考虑传所需要的参数,所以只能另外引入需要的变量.
适配器就是通过构造方法让用户传入需要的参数对象而已.
三孔插头和两孔插座的问题.