例子摘自 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方法是固定的.不能從入參去考慮傳所需要的參數,所以只能另外引入需要的變量.
適配器就是通過構造方法讓用戶傳入需要的參數對象而已.
三孔插頭和兩孔插座的問題.