只要一個(gè)方法操作的是類(lèi)而非接口,那么我們就只能使用這個(gè)類(lèi)及其子類(lèi)了。如果想要將這個(gè)方法應(yīng)用于不在此繼承結(jié)構(gòu)中的某個(gè)類(lèi),那就會(huì)導(dǎo)致失敗。接口可以在很大程度上放寬這種限制,因此,接口能使我們編寫(xiě)可復(fù)用性更好的代碼。
例如有一個(gè)Processor類(lèi),他有一個(gè)name()方法;另外還要一個(gè)process()方法,該方法接受輸入?yún)?shù),修改他的值,然后產(chǎn)生輸出。這個(gè)類(lèi)作為基類(lèi)而被擴(kuò)展,用來(lái)創(chuàng)建各種不同類(lèi)型的Processor。在本例中,Processor的子類(lèi)將修改String對(duì)象(注意,返回類(lèi)型可以是協(xié)變類(lèi)型,而非參數(shù)類(lèi)型):
package interfaces.classprocessor;
import java.util.Arrays;
class Processor {
public String name() {
return getClass().getSimpleName();
}
Object process(Object input) {
return input;
}
}
class Upcase extends Processor {
String process(Object input) {
//Covariant return
return ((String) input).toUpperCase();
}
}
class Downcase extends Processor {
String process(Object input) {
return ((String) input).toLowerCase();
}
}
class Splitter extends Processor {
String process(Object input) {
//the split() arguments divides a String into pices:
return Arrays.toString(((String) input).split(" "));
}
}
public class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Processor " + p.name());
System.out.println(p.process(s));
}
public static String s = "Disagreement with beliefs if by definition incorrect";
public static void main(String[] args) {
process(new Upcase(), s);
process(new Downcase(), s);
process(new Splitter(), s);
}
}
Apply.process()方法可以接受任何類(lèi)型的Processor,將其應(yīng)用到一個(gè)Object對(duì)象上,然后打印結(jié)果。創(chuàng)建一個(gè)能夠根據(jù)所傳遞的參數(shù)對(duì)象的不同而執(zhí)行不同行為的方法,被稱(chēng)為策略模式。這種方法包含所要執(zhí)行的算法中固定不變的部分,而“策略”包含在變化的部分。策略就是傳遞進(jìn)去的參數(shù)對(duì)象,它包含索要執(zhí)行的代碼。這里Processor對(duì)象就是一個(gè)策略,在main方法中,可以看到有三種不同類(lèi)型的策略應(yīng)用到了String類(lèi)型的s對(duì)象上。
split()方法是String類(lèi)型的一部分,他接受String類(lèi)型的對(duì)象,并以傳遞進(jìn)來(lái)的參數(shù)作為邊界,將該String類(lèi)型的對(duì)象分割開(kāi),然后返回一個(gè)數(shù)據(jù)String[]。它在這里被用來(lái)當(dāng)做創(chuàng)建String數(shù)組的快捷方式。
現(xiàn)在假設(shè)我們發(fā)現(xiàn)了一組電子濾波器,他們看起來(lái)好像適用于Apply.process()方法。
package filters;
class Waveform {
private static long counter;
private final long id = counter++;
public String toString() {
return "Waveform " + id;
}
}
package filters;
class Filter {
public String name() {
return getClass().getSimpleName();
}
public Waveform process(Waveform input) {
return input;
}
}
package filters;
public class LowPass extends Filter{
double cutoff;
public LowPass(Double cutoff) {
this.cutoff = cutoff;
}
public Waveform process(Waveform input) {
return input;//Dummy processing
}
}
package filters;
public class HighPass extends Filter {
double cutoff;
public HighPass(double cutoff) {
this.cutoff = cutoff;
}
public Waveform process(Waveform input) {
return input;//Dummy processing
}
}
package filters;
public class BandPass extends Filter {
double lowCutoff, highCutoff;
public BandPass(double lowCutoff, double highCutoff) {
this.lowCutoff = lowCutoff;
this.highCutoff = highCutoff;
}
public Waveform process(Waveform input) {
return input;//Dummy processing
}
}
Filter與Processor具有相同的接口元素,但是因?yàn)樗⒎抢^承自Processor——因?yàn)镕ilter的創(chuàng)建者壓根就不清楚你想要將他用作Processor——因?yàn)槟悴荒軐ilter用于Apply.process()方法,即便這樣可以正常運(yùn)行。這里主要是因?yàn)锳pply.processor()方法和Processor()之間的耦合過(guò)緊,已經(jīng)超出了所需要的程度,這就使得應(yīng)該服用Apply.process()的代碼時(shí),復(fù)用卻被禁止了。另外還需要注意的是,他們的輸出和輸入都是WaveForm。
但是,如果Process是一個(gè)接口,那么這些限制就會(huì)變得松動(dòng),使得你可以復(fù)用該接口結(jié)構(gòu)的Apply.process()。
package interfaceprocessor;
public interface Processor {
String name();
Object process(Object input);
}
package interfaceprocessor;
public class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Process " + p.name());
System.out.println(p.process(s));
}
}
package interfaceprocessor;
import java.util.Arrays;
//復(fù)用代碼的第一種方式是客戶(hù)端程序員遵循該接口來(lái)編寫(xiě)他們自己的類(lèi),
public abstract class StringProcessor implements Processor {
public String name() {
return getClass().getSimpleName();
}
public abstract String process(Object imput);
public static String s = "If she weights the same as a duck, she's made of wood";
public static void main(String[] args) {
Apply.process(new Upcase(), s);
Apply.process(new Downcase(), s);
Apply.process(new Splitter(), s);
}
}
class Upcase extends StringProcessor {
public String process(Object input) {
return ((String) input).toUpperCase();
}
}
class Downcase extends StringProcessor {
public String process(Object input) {
return ((String) input).toLowerCase();
}
}
class Splitter extends StringProcessor {
public String process(Object input) {
return Arrays.toString(((String) input).split(" "));
}
}
但是,你經(jīng)常碰到的情況是你無(wú)法修改你想要使用的類(lèi)。例如,在電子濾波器中,類(lèi)庫(kù)是被發(fā)現(xiàn)而非創(chuàng)建的。在這種情況下,可以使用適配器設(shè)計(jì)模式。適配器中的代碼將接受你所擁有的接口,就像下面這樣:
package interfaceprocessor;
import filters.Filter;
import filters.Waveform;
public class FilterAdapter implements Processor {
Filter filter;
public FilterAdapter(Filter filter) {
this.filter = filter;
}
public String name() {
return filter.name();
}
public Waveform process(Object input) {
return filter.process((Waveform) input);
}
}
package interfaceprocessor;
import filters.BandPass;
import filters.HighPass;
import filters.LowPass;
import filters.Waveform;
public class FilterProcessor {
public static void main(String[] arg) {
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new LowPass(1.0)), w);
Apply.process(new FilterAdapter(new HighPass(2.0)), w);
Apply.process(new FilterAdapter(new BandPass(3.0, 4.0)), w);
}
}
在使用適配器的方式中,F(xiàn)ilterAdapter的構(gòu)造器接受你所擁有的構(gòu)造器Filter,然后生成具有你所需要的Processor()接口的對(duì)象。在FilterAdapter類(lèi)中用到了代理。將接口從具體實(shí)現(xiàn)中解耦使得接口可以應(yīng)用于多種不同的具體實(shí)現(xiàn),因此代碼也更加具有可復(fù)用性。
文章內(nèi)容出自《Thinking in Java》