接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
1 抽象类和抽象方法
抽象类,它是普通类与接口之间的一种中庸之道。
抽象方法是不完整的;仅有声明而没有方法体。包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。
如果一个类,让其包含任何abstract方法都显得没有实际意义,而且我们也想要阻止产生这个类的任何对象,那么这时这样做就很有用了。
2 接口
接口提供了形式,而未提供任何具体实现。接口也可以包含域,这些域隐式地是static和final的。
3 完全解耦
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。如果你想要将这个方法应用于不在此继承结构中的某个类,那么你就会触霉头了。接口可以在很大程度上放宽这种限制,因此,它使得我们可以编写可复用性更好的代码。
//代码来自于Java编程思想 第四版
import java.util.*;
/*
*该类作为基类被扩展,用来创建各种不同类型的Processor;
*/
class Processor{
public String name(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class Upcase extends Processor{
//Covariant return 协变返回类型
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 void process(Processor p,Object s){
System.out.println(p.name());
System.out.println(p.process(s));
}
public static String s = "The flower";
public static void main(String[] args){
process(new Upcase(),s);
process(new Downcase(),s);
process(new Splitter(),s);
}
}
/*
运行结果:
Upcase
THE FLOWER
Downcase
the flower
Splitter
[The, flower]
*/
Apply.process()方法可以接受任何类型的Processor,并将其应用到一个Object对象上,然后打印结果。Apply.process()与Processor之间的耦合过紧,如果Processor是一个接口,那么这些限制就会变得松动。
像本例这样,创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式。这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。这里,Processor对象就是一个策略,在main()中可以看到有三种不同类型的策略应用到了String类型的s对象上。
4 接口与工厂
接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现。
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Imp1 implements Service{
public void method1(){
System.out.println("Imp1 method1");
}
public void method2(){
System.out.println("Imp1 method2");
}
}
class Imp1Factory implements ServiceFactory{
public Service getService(){
return new Imp1();
}
}
//不同类
class Imp2 implements Service{
public void method1(){
System.out.println("Imp2 method1");
}
public void method2(){
System.out.println("Imp2 method2");
}
}
class Imp2Factory implements ServiceFactory{
public Service getService(){
return new Imp2();
}
}
public class Factories{
public static void serviceConsumer(ServiceFactory fact){
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(new Imp1Factory());
//改变传入对象
serviceConsumer(new Imp2Factory());
}
}
/*
*执行结果:
Imp1 method1
Imp1 method2
Imp2 method1
Imp2 method2
*/
任何抽象性都应该是应真正的需求而产生的。恰当的原则是优先选择类而不是接口。从类开始,如果接口的必需性变得非常明确,那么就进行重构。