前言-
本文是为个人学习做的整理性质的笔记,肯定带有许多不妥的地方,仅供参考。
(第九章·接口 《Thinking in Java》)
接口不仅仅只是一种更纯粹形式的抽象类
正文-
接口不仅仅只是一种更纯粹形式的抽象类,他的目标比这还要高。比如说“完全解耦”和“多重继承”
首先是完全解耦,这个你与要对耦合有一定的了解,只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。
现在我们有个Processor类,它包含name()方法和process()方法。Splitter方法继承Processor并重写process()方法,实现按照空格切分字符串的功能。
在Apply中,Apply.process()方法可以接受任何类型的Processor(只要它继承自Processor),并将其运用到一个Object对象上,然后打印结果。
class Processor { public String name() { return getClass().getSimpleName(); } Object process(Object input) { return input; } } class Splitter extends Processor{ @Override Object process(Object input) { // TODO 自动生成的方法存根 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="i love you baby"; public static void main(String[] args) { process(new Splitter(),s); } }
※像例子这样的,创建一个能够根据所传参数对象的不同而是用不同行为的方法,被称为策略设计模式。这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分。
※策略就是传进去的参数对象,它包含要执行的代码。这里Processor就是一个策略。
不过这些并不是重点,Splitter的实现也不是重点。
记住Processor的样子!才是重点!
接下来是另一组类
public class Waveform {// 波形类 private static long count; private final long id=count++; public String toString(){ return "Waveform "+id; } } class Filter{// 适配器类 public String name() { return getClass().getSimpleName(); } Object process(Waveform input) { return input; } } class BandPass extends Filter{// 滤波器类 double lowCutoff,hightCutoff; public BandPass(double lowCutoff,double hightCutoff) { // TODO 自动生成的构造函数存根 this.lowCutoff=lowCutoff; this.hightCutoff=hightCutoff; } @Override Object process(Waveform input) { // TODO 自动生成的方法存根 return input; } }
观察Filter类与Processor,她两具有相同的接口元素。如果在mian方法中尝试调用static 的Apply.process(p,s);时,编译器会提示Apply的process(p,s)方法不适用。因为你在将一个方法应用于不在此继承结构中的某个类中。
※此时Apply.process()就与Processor之间的耦合过紧。
使用接口可以很大程度上的放宽这种耦合,现在我们将Processor改成接口类型
public interface iProcessor { String name(); Object process(Object input); } public class StringProcessor implements iProcessor { public static String s="i love you baby"; public static void main(String[] args) { // TODO 自动生成的方法存根 NewApply.process(new Splitter(),s); } @Override public String name() { // TODO 自动生成的方法存根 return getClass().getSimpleName(); } @Override public Object process(Object input) { // TODO 自动生成的方法存根 return input; } } class NewApply{ public static void process(Processor p,Object s) { System.out.println("Using Processor "+p.name()); System.out.println(p.process(s)); } } class NewSplitter extends StringProcessor{ @Override public Object process(Object input) { // TODO 自动生成的方法存根 return Arrays.toString(((String)input).split(" ")); } }
现在Processor被接口化为iProcessor,怎样适用于Wavefform呢?
那就可以采用适配器设计模式。通过适配器Adapter接受你所拥有的接口(类型),并产生你所需要的的接口(类型)。
public class FilterAdapter implements iProcessor { Filter f; public FilterAdapter(Filter f) { // TODO 自动生成的构造函数存根 this.f=f; // 将刚刚的fiter传进来做适配 } @Override public String name() { // TODO 自动生成的方法存根 return f.name(); } @Override public Object process(Object input) { // TODO 自动生成的方法存根 return f.process((Waveform)input); } }
public class FilterProcessor { public static void main(String[] args) { // TODO 自动生成的方法存根 Waveform w=new Waveform(); NewApply.process(new FilterAdapter(new BandPass(3.0, 4.0)), w); } }
就这样Adapter接受了你原来拥有的Filter类型,并产生了一个你急需的iProcessor接口的对象。
※虽然适配器看起来很实用,但是尽量少使用她。当你过多使用适配器转换的时候,就应该反思一下是不是设计出了什么问题。