Java之完全解耦

只要一個(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》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容