求助一个问题 最近在看java编程思想 里面说“将接口从具体实现中解耦使得接口可以应用于多种不同的具体实现,因此代码也就更具可复用性” 可是书中所举的例子用继承具体实现类的方式也可以实现 并不是非得用接口才行 所以比较奇怪接口的优势除了可以多继承和实现外并没有发现比直接继承具体实现类好在哪里 哪位大神能帮我解答一下,下面是具体的代码示例:
java编程思想中的示例:
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。如果你想要将这个方法应用于不在此继承结构中的某个类,那么你就会倒大霉了。接口可以在很大程序上放宽这种限制,因此它使得我们可以编写可复用性更好的代码
首先看,通过类的继承实现的一个程序
class Processor{
    public String name(){
        return getClass().getSimpleName();
    }
    Object process(Object input){
        return input;
    }
}
class Upcase extends Processor{
    String process(Object input){
        return ((String)input).toUpperCase();
    }
}
class Downcase extends Processor{
    String process (Object input){
        return ((String)input).toLowerCase();
    }
}
class Splitter extends Processor{
    String process(Object input){
        return Arrays.toString(((String)input).split(" "));
    }
}public class Apply {
    public static String s = "Disagredment with beliefs is by definition incorrect";
    public static void process(Processor p, Object s){
        System.out.println("Using Processor "+ p.name());
        System.out.println(p.process(s));
    }
    public static void main(String[] args) {
        process(new Upcase(),s);
        process(new Downcase(),s);
        process(new Splitter(),s);    }
}
这个例子很简单,只是把字符串转换为大写,小写和以空格拆分的字符串。值得注意的是负责转换的类Upcase, Downcase和Splitter都是继承于Processor的,而Processor是一个普通的类。咋一看是没问题的,但是要想通过复用把以下的别的类似的程序就不方便了
class Waveform{
    private static long counter;
    private final long id = counter++;
    public String toString(){
        return "Waveform" + id;
    }
}
class Filter{
    public String name(){
        return getClass().getSimpleName();
    }
    public Waveform process(Waveform input){
        return input;
    }
}
class LowPass extends Filter{
    double cutoff;
    public LowPass(double cutoff){
        this.cutoff = cutoff;
    }
    @Override
    public Waveform process (Waveform input){
        return input;
    }
}
class HighPass extends Filter{
    double cutoff;
    public HighPass(double cutoff){
        this.cutoff = cutoff;
    }
    public Waveform process(Waveform input){
        return input;
    }
}
class BandPass extends Filter{
    double lowCutoff,highCutoff;
    public BandPass(double lowCut, double highCut){
        lowCutoff = lowCut;
        highCutoff = highCut;
    }
}
因为在Apply.process()方法在传入的是Processor类,而Filter的创建者压根不清楚它将要被用作Processor。也许你会认为通过继承Process就把问题解决了,但是你会发现Filter.process和Process.process的方法签名是不一样的,那就是说Filter并没有覆盖Process的方法,这样将会导致不安全性(Filter因继承而多了一个不在设计范围内的方法)。因此使得代码复用就很难了,主要的原因是Apply.process()和Process之间的耦合太紧了。如果把Processor改为接口,这些限制就会变得松动了
interface Processor {
    String name();
    Object process(Object input);
}
//把导出类的name方法抽取出来单独设置一个abstract类
abstract class StringProcessor implements Processor{
    public String name(){
        return getClass().getSimpleName();
    }
    public abstract String process(Object input);
}
class Upcase extends StringProcessor {
    @Override
    public String process(Object input) {
        return ((String)input).toUpperCase();
    }
}
class Splitter extends StringProcessor{
    @Override
    public String process(Object input) {
        return Arrays.toString(((String)input).split(" "));
    }
}
class Downcase extends StringProcessor {
    @Override
    public String process(Object input) {
        return ((String)input).toLowerCase();
    }
}
public class Apply {
    public static String s = "Disagredment with beliefs is by definition incorrect";
    public static void process(Processor p, Object s){
        System.out.println("Using Processor "+ p.name());
        System.out.println(p.process(s));
    }
        
    public static void main(String[] args) {
            process(new Upcase(), s);
            process(new Downcase(),s);
            process(new Splitter(),s);
        }
}这种我们就可以通过实现接口而在复用的基础上加入Filter了
abstract class Filter implements Processor {
    public String name() {
        return getClass().getSimpleName();
    }    public abstract Waveform process(Object input);
}
class BandPass extends Filter{
    double lowCutoff,highCutoff;
    public BandPass(double lowCut, double highCut){
        lowCutoff = lowCut;
        highCutoff = highCut;
    }
    @Override
    public Waveform process(Object input) {
        return (Waveform) input;
    }
}
class HighPass extends Filter{
    double cutoff;
    public HighPass(double cutoff){
        this.cutoff = cutoff;
    }
    @Override
    public Waveform process(Object input) {
        return (Waveform) input;
    }
}
class LowPass extends Filter{
    double cutoff;
    public LowPass(double cutoff){
        this.cutoff = cutoff;
    }
    @Override
    public Waveform process (Object input){
        return (Waveform) input;
    }
}
public class Apply {
    public static String s = "Disagredment with beliefs is by definition incorrect";
    public static void process(Processor p, Object s){
        System.out.println("Using Processor "+ p.name());
        System.out.println(p.process(s));
    }
        
    public static void main(String[] args) {
            //process(new Upcase(), s);
            //process(new Downcase(),s);
            //process(new Splitter(),s);
            
            Waveform w = new Waveform();
            process(new LowPass(1.0),w);
            process(new HighPass(3.0),w);
            process(new BandPass(1.0,2.0),w);
        }
}上面的例子很好说明了,不用修改原程序(当然Filter还是要改的),可以直接通过复用接口Processor和Apply.process()。然后有的时候Filter并不是可以修改的,或者你得到的只是一个类库,这个时候可以使用Adaptor设计模式
//Filter不能修改
class Filter{
    public String name(){
        return getClass().getSimpleName();
    }
//    @Override
    public Waveform process(Waveform input){
        return input;
    }
}
//Filter的Adapter
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);
    }
}public class Apply {
    public static String s = "Disagredment with beliefs is by definition incorrect";
    public static void process(Processor p, Object s){
        System.out.println("Using Processor "+ p.name());
        System.out.println(p.process(s));
    }
        
    public static void main(String[] args) {        
            Waveform w = new Waveform();        
            process(new FilterAdapter(new chapter9.LowPass(1.0)),w);
            process(new FilterAdapter(new chapter9.HighPass(3.0)),w);
            process(new FilterAdapter(new chapter9.BandPass(1.0,2.0)),w);
        }
}在这种使用适配器的方式中,FilterAdapter的构造器接受你所拥有的接口Filter,然后生成具有你所需要的Processor接口的对象。在FilterAdapter中还使用了代理下面是我不使用接口实现的方式:
class FilterConver extends Processor{
Filter filter;
public FilterConver(Filter filter) {
this.filter = filter;
}
@Override
Waveform process(Object input) {
// TODO Auto-generated method stub
return filter.process((Waveform)input);
}
}接口

解决方案 »

  1.   

    大概看了一下楼主的代码,按楼之的意图,将Processor设计成抽象类,process方法定义成抽象的,不是也可以吗?
    大家所说的面向接口编程,其实不准确,准确的说,应该叫面向抽象编程,不一定就只是接口。
    个人感觉,抽象类和接口相比,除了不能多继承,其他方面的优势,比接口有过之而无不及。所谓面向接口,其实只是说,让程序依赖于一个比较宽泛的类型,这个类型下面应该有很多具体的子类;也就是说,这个类型处在一个比较大的类型树的顶端。跟他是类还是接口没必然关系。
    如果你设计一个接口,而没有一个类实现它,那你面向这个接口编程有什么意义呢?
    所以,个人的结论是,如果不考虑多继承,java中的接口(仅仅指的是interface这个关键字所代表的含义)的存在完全是个多余。