本文内容参考自Java8标准
再次感谢Java编程思想对本文的启发!
在看这篇博文之前,需要三个知识点作为基础:
⑴、对多态机制完全了解(Java中的所有方法默认都是后期绑定/运行时绑定)。
⑵、Java中的一个类只能继承(extends)一个类。
⑶、Java中的一个类可以同时实现(implements)多个接口。
在Java中,如果一个方法的形式参数是一个普通类/抽象类类型,而不是一个接口,那么你就只能使用这个普通类/抽象类类型或者是它的子类的对象作为实际参数传入这个方法,如果你想要将其它不在继承层次结构中的普通类/抽象类类型或者是子类对象作为实际参数传入这个方法的话,这是行不通的。
接口可以在很大的程度上放宽这种限制,它可以突破继承层次的限制,因此,使用接口可以让我们编写可复用性更好的代码。
举例:
假设有一个Processor类,它有一个name()方法,还有一个process()方法(该方法接受输入参数,修改它的值,然后产生输出)。
现在,将这个Processor类作为父类(基类)来进行扩展,用来创建各种不同类型的Processor。
代码示例:
// 代码示例
//父类Processor
class Processor{
//方法name()
public String name(){
//返回当前类的名称
//getClass().getSimpleName()是反射里面常用的方法
//在这里,你仅将它当成一个普通方法即可。
return getClass().getSimpleName();
}
//方法process(Object input),带一个Object类型的形式参数input
//注意这个方法的返回值,是Object类型。联系到前面说过的
//协变返回类型,也就是说,在子类中,这个方法可以返回任意的类型。
Object process(Object input){
//返回input的值
return input;
}
}
//类Upcase继承类Processor
class Upcase extends Processor{
//根据协变返回类型,在这里返回String类型是合法的。
String process(Object input){
//返回input的值,这里使用了(String)强制转换的形式
//也就是将Object类型向下转型为String类型,还用到了String类型
//的方法toUpperCase(),意味着将字符串中的所有字符都转换成大写
return ((String)input).toUpperCase();
}
}
//类Downcase继承类Processor
class Downcase extends Processor{
//根据协变返回类型,在这里返回String类型是合法的。
String process(Object input){
//返回input的值,这里使用了(String)强制转换的形式
//也就是将Object类型向下转型为String类型,还用到了String类型
//的方法toLowerCase(),意味着将字符串中的所有字符都转换成小写
return ((String)input).toLowerCase();
}
}
//类Splitter继承类Processor
class Splitter extends Processor{
//根据协变返回类型,在这里返回String类型是合法的。
String process(Object input){
//使用(String)强制转换的形式,将input强制转换成String类型
//然后调用了String类型的方法split(String s),实际传入的参数是
//" ",意味着将input根据" "(空格)分段,只要有" "就分段
//返回一个String数组类型(String[]),而后再将这个返回的String数组
//作为实际参数传入类Arrays的static方法toString(String[] s)中
//直接返回一个字符串(也就是将String数组作为String类型打印输出)。
return Arrays.toString(((String)input).split(" "));
}
}
//---------------------------------------------------------------------
//下面的代码类似框架,是对上面的类的应用
public class Apply{
//方法process(Processor p,Object s),有一个Processor类型
//和String类型两个形式参数。
//注意,在调用这个方法的时候,实际参数可以是Processor类型,也可以是它
//的子类型
public static void process(Processor p,Object s){
//输出字符串以及对象p的name()方法返回值"Using Processor" + p.name()
System.out.println("Using Processor" + p.name());
//返回对象p调用方法process(Object input)的返回值
System.out.println(p.process(s));
}
//测试字符串s
public static String s = "Disafreement with beliefs is by
definition incorrect";
//程序执行入口main方法
public static void main(String[] args){
//调用方法process(Processor p,Object s)
//传入实际参数类Upcase的对象(类Processor的子类),以及字符串s
process(new Upcase(),s);
//调用方法process(Processor p,Object s)
//传入实际参数类Downcase的对象(类Processor的子类),以及字符串s
process(new Downcase(),s);
//调用方法process(Processor p,Object s)
//传入实际参数类Splitter的对象(类Processor的子类),以及字符串s
process(new Splitter(),s);
}
}
结果示例:
三个子类,三种实现,三种应用:
类Apply的方法process(Processor p,Object s)可以接受任何类型的Processor(Processor以及它的子类),并将其应用到一个Object对象上,然后打印结果。
像上面代码示例中一样,创建一个能够根据所传递的实际参数对象类型的不同而具有不同行为的方法(类Upcase、类DownCase、类Splitter三个子类分别对方法process()有三种不同的实现),这种叫做策略模式,这类方法包含所以要执行的算法中固定不变的部分(就是类Apply的方法process(Processor p,Object s)),而"策略"包含变化的部分,策略就是传递的实际对象(类Upcase、类DownCase、类Splitter三个子类),它包含要执行的代码。
在上面的示例代码中,Processor对象就是一个策略,在方法main()中可以看到三种不同类型的策略应用到了String类型的对象s上。
下面将提出父类Processor(基类)面临的最大挑战。
下面将提出父类Processor(基类)面临的最大挑战。
下面将提出父类Processor(基类)面临的最大挑战。
重要的事情说三遍…
除了以上已经实现的三个子类(类Upcase、类DownCase、类Splitter)之外,现在准备扩展。
假设,我们发现了一组电子滤波器,它们看起来好像适用于类Apply的process(Processor p,Object s)方法:
代码示例:
// 扩展
//父类Waveform,代表电子,与上面示例代码中的父类Processor对应
public class Waveform{
//类变量counter
private static long counter;
//类变量id,初始化值为当前的类变量counter++表达式的值
private final long id = counter++;
//方法toString()
public String toString(){
//返回字符串"Waveform" + id
return "Waveform" + id;
}
}
//父类Filter,代表滤波器,表示了具体的应用,与上面示例代码中的类Apply对应
public class Filter{
//方法name()
public String name(){
//返回方法getClass().getSimpleName()的结果
reutnr getClass().getSimpleName();
}
//方法process(Waveform input),带一个Waveform类型的形式参数input
//这个方法的返回类型是Waveform,根据协变返回类型,子类在实现的时候
//可以返回Waveform类型或者它的子类型
public Waveform process(Waveform input){
//返回input的值。
return input;
}
}
//类LowPass继承类Filter,代表低频滤波器。
public class LowPass extends Filter{
//double类型类变量cutoff
double cutoff;
//构造方法,带一个double类型的形式参数
public LowPass(double cutoff){
//初始化类变量cutoff
this.cutoff = cutoff;
}
//方法process(Waveform input),带一个Waveform类型的形式参数input
//这个方法的返回类型是Waveform,根据协变返回类型,子类在实现的时候
//可以返回Waveform类型或者它的子类型
public Waveform process(Waveform input){
//返回input的值。
return input;
}
}
//类HightPass继承类Filter,代表高频滤波器。
public class HightPass extends Filter{
//double类型类变量cutoff
double cutoff;
//构造方法,带一个double类型的形式参数
public HightPass(double cutoff){
//初始化类变量cutoff
this.cutoff = cutoff;
}
//方法process(Waveform input),带一个Waveform类型的形式参数input
//这个方法的返回类型是Waveform,根据协变返回类型,子类在实现的时候
//可以返回Waveform类型或者它的子类型
public Waveform process(Waveform input){
//返回input的值。
return input;
}
}
//类BandPass继承类Filter,代表双频滤波器。
public class BandPass extends Filter{
//double类型类变量lowcutoff,hightcutoff
double lowcutoff,hightcutoff
//构造方法,带一个double类型的形式参数
public BandPass(double lowCut,double hightCut){
//初始化类变量cutoff
lowcutoff = lowCut;
hightcutoff = hightCut;
}
//方法process(Waveform input),带一个Waveform类型的形式参数input
//这个方法的返回类型是Waveform,根据协变返回类型,子类在实现的时候
//可以返回Waveform类型或者它的子类型
public Waveform process(Waveform input){
//返回input的值。
return input;
}
}
单纯从代码的角度来看,类Filter和类Processor具有相同的接口元素(都有方法name()和方法process()),但是因为类Filter并非继承自类Processor-----可能是类Filter的创建者事先或者压根不知道还有另外的一个这么相似的类Processor,也不知道有可能会有将类Filter当做类Processor使用的机会。
从目前的架构来看,你不能将类Filter用于类Apply的process(Processor p,Object s)方法(你自己可以自行尝试为什么不可以),主要是因为类Apply的方法process(Processor p,Object s)与类Processor之间的耦合过紧(仅允许类Processor或者是它的子类),已经超出了所需要的程度。这就使得想复用类Apply的方法process(Processor p,Object s)的代码时被禁止了。
这里你还需要注意一个问题:类Filter的方法process(Waveform input)的返回值类型是Waveform,而类Processor的方法process(Processor p,Object s)返回值为void。
如果类Processor是一个接口,那么类Apply的方法process(Processor p,Object s)与类Processor之间的限制就会变得松动,使得方法process(Processor p,Object s)的使用会变得更宽泛起来。下面是改进后的代码示例:
// 用接口解耦
//接口Processor,关键字是interface而不是class了。
public interface Processor{
//行为一:name()
String name();
//行为二:process(Object input)
Object process(Object input);
}
//下面的代码类似框架。
public class Apply{
//方法process(Processor p,Object s),有一个Processor类型
//和String类型两个形式参数。
//注意,在调用这个方法的时候,实际参数只能是实现了接口Processor
//的子类型
public static void process(Processor p,Object s){
//输出字符串以及对象p的name()方法返回值"Using Processor" + p.name()
System.out.println("Using Processor" + p.name());
//返回对象p调用方法process(Object input)的返回值
System.out.println(p.process(s));
}
}
//-------------------------------------------------------------------
//1、复用代码的第一种方式是客户端程序员遵循该接口来编写他们自己的类:
//抽象类StringProcessor实现接口Processor
public abstract class StringProcessor implements Processor{
//方法name()
public String name(){
//返回方法getClass().getSimpleName()的结果
reutnr getClass().getSimpleName();
}
//将方法process()设置为抽象方法,让子类去继承实现
public abstract String process();
//测试字符串s
public static String s = "If she weighs ths same as a duck
,she`s made of wood";
//程序执行入口main方法
public static void main(String[] args){
//调用方法process(Processor p,Object s)
//传入实际参数类Upcase的对象(接口Processor的子类),以及字符串s
process(new Upcase(),s);
//调用方法process(Processor p,Object s)
//传入实际参数类Downcase的对象(接口Processor的子类),以及字符串s
process(new Downcase(),s);
//调用方法process(Processor p,Object s)
//传入实际参数类Splitter的对象(接口Processor的子类),以及字符串s
process(new Splitter(),s);
}
}
//类Upcase继承抽象类StringProcessor
class Upcase extends StringProcessor{
//根据协变返回类型,在这里返回String类型是合法的。
String process(Object input){
//返回input的值,这里使用了(String)强制转换的形式
//也就是将Object类型向下转型为String类型,还用到了String类型
//的方法toUpperCase(),意味着将字符串中的所有字符都转换成大写
return ((String)input).toUpperCase();
}
}
//类Downcase继承抽象类StringProcessor
class Downcase extends StringProcessor{
//根据协变返回类型,在这里返回String类型是合法的。
String process(Object input){
//返回input的值,这里使用了(String)强制转换的形式
//也就是将Object类型向下转型为String类型,还用到了String类型
//的方法toLowerCase(),意味着将字符串中的所有字符都转换成小写
return ((String)input).toLowerCase();
}
}
//类Splitter继承抽象类StringProcessor
class Splitter extends StringProcessor{
//根据协变返回类型,在这里返回String类型是合法的。
String process(Object input){
//使用(String)强制转换的形式,将input强制转换成String类型
//然后调用了String类型的方法split(String s),实际传入的参数是
//" ",意味着将input根据" "(空格)分段,只要有" "就分段
//返回一个String数组类型(String[]),而后再将这个返回的String数组
//作为实际参数传入类Arrays的static方法toString(String[] s)中
//直接返回一个字符串(也就是将String数组作为String类型打印输出)。
return Arrays.toString(((String)input).split(" "));
}
}
//------------------------------------------------------------------
//用适配器模式解耦
//你经常会遇到的情况是你无法修改你想要使用的类,例如,在上面的电子滤波器例子中,
//类库是被发现而不是被创建的(也就是说放你发现了一个合适的,
//但是不能去按需修改),在这样的情况下,就可以使用适配器模式。
//适配器中的代码将接受你所拥有的接口,并产生你需要的接口。
//代码示例:
//类FilterAdapter实现接口Processor
class FilterAdapter implements Processor{
//从这个形式看,就是组合,既然不能修改Filter的代码,就利用组合了。
//在组合它的基础上再进行一个包装或者改进
//这里组合了一个类Filter(拿来即用)
Filter filter;
//构造方法FilterAdapter(Filter filter),带一个Filter类型的形式参数
//也就是说在类FilterAdapter创建对象的时候,通过构造方法注入一个
//类Filter的对象进来,以实现组合的目的
public FilterAdapter(Filter filter){
//初始化类Filter
this.filter = filter;
}
//方法name()
public String name(){
//直接使用类Filter对象调用类Filter方法name的结果。
//使用了代理
return filter.name();
}
//方法process(Object input),带一个Object类型的形式参数input
public Waveform process(Object input){
//直接返回类Filter对象调用类Filter方法process(Object input)的结果。
//使用了代理,(Waveform)进行了强制转换
return filter.process((Waveform)input);
}
}
//测试类FilterProcessor
public class FilterProcessor{
//程序执行入口main方法
public static void main(String[] args){
//创建类Waveform的对象实例
Waveform w = new Waveform();
//调用类Apply的方法process(Processor p,Object s)
//传入实际参数是接口Processor的子类FilterAdapter以及Object的子类
//Waveform
Apply.process(new FilterAdapter(new LowPass(1.0)),w);
//传入实际参数是接口Processor的子类FilterAdapter以及Object的子类
//Waveform
Apply.process(new FilterAdapter(new HightPass(2.0)),w);
//传入实际参数是接口Processor的子类FilterAdapter以及Object的子类
//Waveform
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)),w);
}
}
//这里省略了类Filter的子类LowPass、子类HightPass、子类BandPass
//的代码,第二个代码示例中都有。
在这种使用适配器的方式中,FilterAdapter的构造器接受你所拥有的接口Filter,然后生成具有你所需要的Processor接口的对象(类FilterAdapter实现了接口Processor,实际上,它就是一个Processor了)。
将接口从具体实现中解耦使得接口可以应用于多种不同的具体实现,因此代码也就更具可复用性。
PS:时间有限,有关Java SE的内容会持续更新!今天就先写这么多,如果有疑问或者有兴趣,可以加QQ:2649160693,并注明CSDN,我会就博文中有疑义的问题做出解答。同时希望博文中不正确的地方各位加以指正。