很早就看到了Java编程思想的接口这章,一直没有找有空的时间把它总结出来,现在倒回去总结一下Java为什么要有接口以及接口是如何带来代码优雅之美的和接口的特殊之处?
1接口是一种模板,是从多个相似类中抽象出来的规范,不提供任何实现,它能体现出是规范和实现分离的设计哲学,从而达到减少代码量以及减少代码依赖来达到更好的维护性以及遵循开放和封闭原则。
下面是一种适配器设计模式例子,是怎么样结合接口来达到上面的特点:
假如有一个Store类,它有一个name()方法;另外还有一个process()方法,该方法接受输入参数,修改它的值,然后产生输出。这个类作为基类而被扩展,用来创建各种不同类型的Store类。客户只知道可以通过Custom类的process方法去传入各种Store类来去获取其地址信息和电话号码,而不知道其他类的功能。目前有三个Store类型的子类,分别是FruitStore类,AppleStore类,SonyStore类。
现在我先不用接口来实现这些客户需求。
public class Store
{
/**
* 返回具体类名
*/
public String name()
{
return getClass().getSimpleName();
}
/**
* 查询店铺的信息
*/
Object info(){return null;};
}
public class FruitStore extends Store
{
String info()
{
return "地址位于深圳"+" 电话:1201250";
}
}
public class AppleStore extends Store
{
String info()
{
return "地址位于纽约"+" 电话:101010";
}
}
public class SonyStore extends Store
{
String info()
{
return "地址位于日本"+" 电话:101000";
}
}
public class CustomStore
{
public static void process(Store store)
{
System.out.println("Using Store"+store.name());
System.out.println(store.info());
}
public static void main(String[] args)
{
process(new FruitStore());
process(new AppleStore());
process(new SonyStore());
}
}
这样写不是搞定了吗,问题来,有一天老板说,能不能让客户来查询我们生产工厂Factory类的信息,我们有三个工厂,分别是Factory1,Factory2,Factory3。具体已有的代码:
public class Factory
{
/**
* 返回具体类名
*/
public String name()
{
return getClass().getSimpleName();
}
/**
* 查询工厂所用的材料
*/
Object info(){return null;};
}
public class Factory1 extends Factory
{
Object info()
{
return "橘子,苹果,芒果";
};
}
public class Factory2 extends Factory
{
Object info()
{
return "芯片,感应光片";
};
}
public class Factory3 extends Factory
{
Object info()
{
return "相机,摄像头";
};
}
天啊,之初没想到老板会提出这样的要求,Factory没有继承Store类啊,怎么把Factory的信息加到里面,让客户只通过Custom类的process方法去查询,现在怎么办啊,难道要改代码吗?于是员工beyondboy去询问同学说,你这之前设计怎么不用接口呢?如果像你这样设计的代码,如果要扩张其他的不是Store类的功能,基本上都要修改你的源代码,这完全不符合面向对象设计开放与关闭原则。beyondboy苦苦的要求下,该同学给出另一种设计思路,这里我画个UML图来描述:
同学说利用接口和组合实现上面的UML图设计思路了从而实现接口带来优雅之美。具体代码如下:
public interface Store
{
/**
* 返回具体类名
*/
public String name();
/**
* 查询店铺的信息
*/
Object info();
}
public abstract class SubStore implements Store
{
/**
* 返回具体类名
*/
public String name()
{
return getClass().getSimpleName();
}
/**
* 查询店铺的信息
*/
public abstract String info();
}
public class AppleStore extends SubStore
{
public String info()
{
return "地址位于纽约"+" 电话:101010";
}
}
public class FruitStore extends SubStore
{
public String info()
{
return "地址位于深圳"+" 电话:1201250";
}
}
public class SonyStore extends SubStore
{
public String info()
{
return "地址位于日本"+" 电话:101000";
}
}
/**
* 这里利用了组合,如果还不知道什么是组合,可以上网搜一下,
* 我也在竞考网上曾发布过组合相关编程题目,有兴趣可以复制下面链接
* http://www.jingkao.net/question/quiz/index/AC112A0136205A9014942E0187473FCA
*/
public class FactoryAdapter implements Store
{
Factory factory;
public FactoryAdapter(Factory factory)
{
this.factory=factory;
}
@Override
public String name()
{
return factory.name();
}
@Override
public Object info()
{
return factory.info();
}
}
public class CustomStore
{
public static void process(Store store)
{
System.out.println("Using Store"+store.name());
System.out.println(store.info());
}
public static void main(String[] args)
{
process(new FruitStore());
process(new AppleStore());
process(new SonyStore());
process(new FactoryAdapter(new Factory1()));
process(new FactoryAdapter(new Factory2()));
process(new FactoryAdapter(new Factory3()));
}
}
运行结果:
按照这样的设计思路,以后你要扩张查询范围,只需写个适配器,而不用修改源码就可以,实现解耦以及减少代码依赖程度的要求,完全符合了面向对象的开放与封闭原则。这是Java的接口带来的代码优雅之美之一。
2接口能实现Java中的多重继承(这里我要做个说明,实际上Java并不支持真正想C++那样意义上的多继承,Java是一种单继承一个实现接口或多个实现接口的语言),这里所说的多重继承,是可以以实现一个类向上转型多个类。
代码实例:
public interface CanFight
{
void fight();
}
public interface CanSwim
{
void swim();
}
public interface CanFly
{
void fly();
}
public class ActionCharacter
{
public void fight()
{
System.out.println("航飞");
}
}
public class Hero extends ActionCharacter implements CanFight, CanFly, CanSwim
{
@Override
public void swim()
{
System.out.println("游泳");
}
@Override
public void fly()
{
System.out.println("飞走");
}
public static void t(CanFight x){x.fight();};
public static void u(CanSwim x){x.swim();};
public static void v(CanFly x){x.fly();};
public static void w(ActionCharacter x){x.fight();};
public static void main(String[] args)
{
Hero hero=new Hero();
t(hero);
u(hero);
v(hero);
w(hero);
}
}
3可以通过继承来扩张接口,这里的extends关键字不同于平时用的,只在接口继承当中,extends可以引用多个基类接口。
代码实例:
public interface CanFight
{
void fight();
}
public interface CanSwim
{
void swim();
}
public interface CanFly extends CanFight,CanSwim
{
void fly();
}
public class ActionCharacter
{
public void fight()
{
System.out.println("航飞");
}
}
public class Hero extends ActionCharacter implements CanFly
{
@Override
public void swim()
{
System.out.println("游泳");
}
@Override
public void fly()
{
System.out.println("飞走");
}
public static void t(CanFight x){x.fight();};
public static void u(CanSwim x){x.swim();};
public static void v(CanFly x){x.fly();};
public static void w(ActionCharacter x){x.fight();};
public static void main(String[] args)
{
Hero hero=new Hero();
t(hero);
u(hero);
v(hero);
w(hero);
}
}
4嵌套接口:
1仅在普通类或抽象类才可以用private修饰内部的嵌套接口,且该嵌套接口不能被外部类访问,而且private接口不能在定义它的类之外被实现。
2接口里所有的接口元素都必须是public,不能用private修饰。
3实现某个接口时不需要实现嵌套在其内部的任何接口以及实现嵌套接口时不需要实现外部接口的方法。
代码例子:
public class A
{
interface B
{
void f();
}
public class Bimp implements B
{
public void f()
{
System.out.println("Bimp");
};
}
public class Bimp2 implements B
{
public void f()
{
System.out.println("Bimp2");
};
}
public interface C
{
public void f();
}
class Cimp implements C
{
public void f()
{
System.out.println("Cimp");
}
}
class Cimp2 implements C
{
public void f()
{
System.out.println("Cimp2");
}
}
private interface D
{
void f();
}
private class Dimp implements D
{
public void f(){System.out.println("Dimp");};
}
public class Dimp2 implements D
{
public void f(){System.out.println("Dimp2");};
}
public D getD()
{
return new Dimp2();
}
private D dRef;
public void receiveD(D d)
{
dRef=d;
dRef.f();
}
}
interface E
{
interface G
{
void f();
}
public interface H
{
void f();
}
void g();
//编译不能通过,因为接口里的成员变量修饰符只能是public。
//!private interfaceI{}
}
public class NestingInterfaces
{
public class Bimp implements A.B
{
@Override
public void f()
{
System.out.println("NestingInterfaces:Bimp");
}
}
class Cimp implements A.C
{
public void f()
{
System.out.println("NestingInterfaces:Cimp");
}
}
//编译不能通过,因为D私有的不能被外部访问
/*class Dimp implements A.D
{
public void f()
{
}
}*/
class Eimp implements E
{
@Override
public void g()
{
System.out.println("NestingInterfaces:Eimp");
}
}
class EGImp implements E.G
{
public void f()
{
System.out.println("NestingInterfaces:EGImp");
}
}
class EImp2 implements E
{
class EG implements E.G
{
public void f()
{
System.out.println("NestingInterfaces:EGImp");
}
}
@Override
public void g()
{
System.out.println("NestingInterfaces:EImp2");
}
}
public static void main(String[] args)
{
A a=new A();
// 不能访问该私有接口,既不能把它当做变量名。
//!A.D ad=a.getD();
//父类类型向下转型,需要强转
//!A.Dimp2 di2=a.getD();
// 不能访问该私有接口,
//!a.getD().f();
A a2=new A();
a2.receiveD(a.getD());
}
}
这篇博客的参考资料:
Java编程思想
HeadFirst设计模式