Java接口之完全解藕
[来源] 达内 [编辑] 达内 [时间]2012-10-30
接口将抽象类更进了一步,它提供了完全的抽象方法,没有任何的实现方法。接口的意义是继承自这个接口的类应该看起来是这样的。任何使用这个接口的用户都知道有哪些方法可以调用,因此接口实际上是被用来定义了类之间交互的一种协议。
但是,接口不仅仅是抽象类的一种极端情况,它还可以允许实现多重继承,使得类可以上塑造型到多个不同的基类型。
接口里面也可以包含域,但是这些域被隐式地作为静态的和final来看待。接口中的方法应该定义为public,不过即使不显式定义为public也会默认的作为public来处理,因此当你继承一个接口,接口中的方法应该定义为public,否则为默认的包控制权限,这样会限制对接口方法的访问,编译器将不会允许。
// : interfaces/music5/ // Interfaces. package interfaces.music5; import .Note; import static net.mindview.util.Print.*; interface Instrument { // Compile-time constant: int VALUE = 5; // static & final // Cannot have method definitions: void play(Note n); // Automatically public void adjust(); } class Wind implements Instrument { public void play(Note n) { print( this + ".play() " + n); } public String toString() { return "Wind"; } public void adjust() { print( this + ".adjust()"); } } class Percussion implements Instrument { public void play(Note n) { print( this + ".play() " + n); } public String toString() { return "Percussion"; } public void adjust() { print(this + ".adjust()"); } } class Stringed implements Instrument { public void play(Note n) { print( this + ".play() " + n); } public String toString() { return "Stringed"; } public void adjust() { print(this + ".adjust()"); } } class Brass extends Wind { public String toString() { return "Brass"; } } class Woodwind extends Wind { public String toString() { return "Woodwind"; } } public class Music5 { // Doesn’t care about type, so new types // added to the system still work right: static void tune(Instrument i) { // ... (Note.MIDDLE_C); } static void tuneAll(Instrument[] e) { for (Instrument i : e) tune(i); } public static void main(String[] args) { // Upcasting during addition to the array: Instrument[] orchestra = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind() }; tuneAll(orchestra); } } /* Output: () MIDDLE_C () MIDDLE_C () MIDDLE_C () MIDDLE_C () MIDDLE_C */// :~
不管是一般类还是抽象类还是接口,在上塑造型的使用上是没有区别的,从代码中我们可以看出来,在tune方法中,是不区分Instrument是一般类还是抽象类或者是接口的。
完全解藕
使用类继承的时候,方法只能针对这个系列的层次引用,其它基类的继承层级,即使是具有相同的方法也不能使用。但是接口却可以跨过这个限制,看下面的代码:
// : interfaces/classprocessor/ package interfaces.classprocessor; import java.util.*; import static net.mindview.util.Print.*; 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() argument divides a String into pieces: return Arrays.toString(((String)input).split(" ")); } } public class Apply { public static void process(Processor p, Object s) { print( "Using Processor " + ()); print(p.process(s)); } public static String s = "Disagreement with beliefs is by definition incorrect" ; public static void main(String[] args) { process(new Upcase(), s); process(new Downcase(), s); process(new Splitter(), s); } } /* Output: Using Processor Upcase DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT Using Processor Downcase disagreement with beliefs is by definition incorrect Using Processor Splitter [Disagreement, with, beliefs, is, by, definition, incorrect] *///:~
创建一个方法,根据传递参数的不同来实现不同的算法称之为策略模式,方法内包含了不同算法的相同的固定的部分,传递的策略参数里面包含了不同的算法。将策略作为参数传递到方法内部,策略里面包含了算法中需要执行的部分。下面再来看下面的代码:
// : interfaces/filters/ package interfaces.filters; public class Waveform { private static long counter; private final long id = counter++; public String toString() { return "Waveform " + id; } } ///:~ // : interfaces/filters/package interfaces.filters; public class Filter { public String name() { return getClass().getSimpleName(); } public Waveform process(Waveform input) { return input; } } ///:~ // : interfaces/filters/package interfaces.filters; public class LowPass extends Filter { double cutoff; public LowPass(double cutoff) { this.cutoff = cutoff; } public Waveform process(Waveform input) { return input; // Dummy processing } } // /:~ // : interfaces/filters/ package interfaces.filters; public class HighPass extends Filter { double cutoff; public HighPass(double cutoff) { this.cutoff = cutoff; } public Waveform process(Waveform input) { return input; } } // /:~ // : interfaces/filters/ package interfaces.filters; public class BandPass extends Filter { double lowCutoff, highCutoff; public BandPass(double lowCut, double highCut) { lowCutoff = lowCut; highCutoff = highCut; } public Waveform process(Waveform input) { return input; } } ///:~
Filter具有与Processor一样的接口,但是它并不是从Processor继承的,因此不能将Filter应用到Apply.process方法中,Apply.process和Processor的耦合过大,阻碍了process方法的重用。但是如果Processor是个接口的话,那么耦合度就足够松散,可以对process方法进行重用,看下面的修改后的代码:
// : interfaces/interfaceprocessor/ package interfaces.interfaceprocessor; public interface Processor { String name(); Object process(Object input); } ///:~ // : interfaces/interfaceprocessor/package interfaces.interfaceprocessor; import static net.mindview.util.Print.*; public class Apply { public static void process(Processor p, Object s) { print( "Using Processor " + ()); print(p.process(s)); } } ///:~
// : interfaces/interfaceprocessor/String package interfaces.interfaceprocessor; import java.util.*; public abstract class StringProcessor implements Processor{ public String name() { return getClass().getSimpleName(); } public abstract String process(Object input); public static String s = "If she weighs 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) { // Covariant return 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(" ")); } } /* Output: 228 Thinking in Java Bruce Eckel Using Processor Upcase IF SHE WEIGHS THE SAME AS A DUCK, SHE’S MADE OF WOOD Using Processor Downcase if she weighs the same as a duck, she’s made of wood Using Processor Splitter [If, she, weighs, the, same, as, a, duck,, she’s, made, of, wood] */// :~
对于使用Filter的时候,可以使用适配器模式,将一种接口转换为另一种接口,如下:
// : interfaces/interfaceprocessor/Filter package interfaces.interfaceprocessor; import interfaces.filters.* ; class FilterAdapter implements Processor { Filter filter; public FilterAdapter(Filter filter) { this.filter = filter; } public String name() { return (); } public Waveform process(Object input) { return filter.process((Waveform)input); } } public class FilterProcessor { public static void main(String[] args) { 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); } } /* Output: Using Processor LowPass Waveform 0 Using Processor HighPass Waveform 0 Using Processor BandPass Waveform 0 *///:~
从这里我们可以看出同一个接口可以有多种不同的实现,能够让你的代码具有更好的重用性能。
Java中的多重继承
因为接口没有任何有意义的实现,所以接口不分配内存,这样就可以 多个接口进行组合。如果一个派生类是继承自类或者抽象类的时候,只能继承一个,如果继承自接口的话,那么可以继承自多个接口,而且在上塑造型的话可以转化为任何一个接口,但是如果是同时继承自接口和类的话,那么一定要先写类在写接口,如下:
// : interfaces/ // Multiple interfaces. interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void swim() {} public void fly() {} } public class Adventure { public static void t(CanFight x) { x.fight(); } public static void u(CanSwim x) { x.swim(); } public static void v(CanFly x) { (); } public static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); // Treat it as a CanFight u(h); // Treat it as a CanSwim v(h); // Treat it as a CanFly w(h); // Treat it as an ActionCharacter } } // /:~