接口和内部类为我们提供了一种将接口和实现分离得更加结构化的方法。
抽象类:
- 抽象类是普通类和接口之间的一种中庸之道。
- 抽象类是建立起一种通用接口,以此表示所有导出类的共同部分,仅有声明没有方法体,抽象基类的抽象方法不提供任何的具体实现,由继承自抽象类的具体类来实现。
- 创建抽象类是希望通过这个通用接口来操纵一系列类。
abstract void f();
- 抽象类中不一定有抽象方法,但是含有抽象方法的类肯定是抽象类。
从一个抽象类继承,必须为基类中的所有抽象方法提供方法定义(子类要实现抽象方法)。 - 抽象类只能被继承,不能被实例化。
创建一个不含任何抽象方法的抽象类的意义:阻止产生这个类的任何对象。
创建抽象类和抽象方法非常有用,因为它们可以使类的抽象性明确起来。抽象类还是很有用的重构工具。
接口:
接口可以用来扩展普通类。如果相要将方法应用于不仅限于某个继承结构中的类,就可以用接口,可以很大程度上放宽限制。 接口可以使得编写可复用性好的代码。
接口是更加纯粹的抽象类,接口根本就没有任何具体实现。
接口是java的伪多重继承方式
interface Instrument{
int value=5;
void play(Note n);
void adjust();
}
- interface接口其实就是一个完全抽象的类,它里面所有的方法都是抽象的,即使不指定abstract关键字,也是隐含的认为这是一个抽象方法。
- interface是极度抽象的类。同时,接口的实现看起来和类一样,可以有访问权限控制,默认是包访问权限,且任何使用某特定接口的代码都知道可以调用该接口的哪些方法。接口中的抽象方法都得是public的,默认也是public,如果不声明为public,那么实现接口的类则访问不到。
- 接口中出抽象方法外,还可以包含的域、变量,这些域、对象隐式的认为都是static或者final的。(因为抽象类只能被继承,不能被实例化,所以它的成员变量必须随着类的加载而加载)
- interface接口实现了java的多重继承的特性。
1、策略设计模式
class Processor{
public String name(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class Upcase extends Processor{
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(""));
}
}
//根据Processor的不同而具有不同行为,策略就是传递进去的参数对象。
public class Apply{
public static void process(Processor p,Object s){
p.process(s);//发生关联
}
}
因为策略设计模式过高的耦合度,不能改写接口的抽象方法,代码复用性不好,所以改用抽象类实现接口,继承自抽象类的具体类改写接口的实现方法。这样代码的复用性高。
class Processor{
public String name();
Object process(Object input);
}
public abstract class StringProcessor implements Processor{
public String name(){
return getClass().getSimpleName();
}
public abstract String process(Object input);
}
class Upcase extends StringProcessor{
String process(Object input){
return ((String)input).toUpperCase();
}
}
class Downcase extends StringProcessor{
String process(Object input){
return ((String)input).toLowerCase();
}
}
class Splitter extends StringProcessor{
String process(Object input){
return Arrays.toString(((String)input).split(""));
}
}
public class Apply{
public static void process(Process p,Object s){
p.process(s);//参数p的具体实现方法是由程序员自己实现的,可复用性高一些。
}
}
策略设计模式耦合度高。
2、适配器设计模式
当类库是被发现而非被创建的,无法修改想要使用的类,就可以使用适配器设计模式,在适配器中实现接口,返回生成的所需要的实现接口的对象
class FilterAdatpter implements Processor{
Filter filter;
public FilterAdatpter(Filter filter){
this.filter=filter;
}
public waveform process(Object input){
return filter.process((waveform)input);
//生成某一个具体的对象
}
}
public FilterProcessor(){
public static void main(String[] args){
waveform w=new waveform();
Apply.process(new FilterAdapter(new Lowcase(1.0)),w);
}
}
适配器设计模式其实就是把类型转换放到适配器中去(在适配器中返回具体类,如Upcase,Downcase、Splitter),具体调用的时候不需要再考虑使用哪个具体类,会由适配器来进行转换。
什么是适配器呢?就是把具体使用哪个接口包装在一个类里面,上层调用者无需关心是哪个接口实现方法、接口的具体实现方法。
适配器类其实用到了代理。将接口从具体实现中解耦,提高代码的可复用性。
接口的一种常用方法就是策略设计模式,还可以使用适配器模式,适配器模式让任何类都可以对该方法进行适配,这就是接口而不是类的强大之处。
接口组合
- 可以将一个类和多个接口组合在一起,产生一个新类。
- 接口的作用:和抽象类一样,防止客户端程序员创建类的对象,确保仅仅只是建立了一个接口
- 接口继承的作用:通过继承可以组合数个接口,因为接口里都是抽象方法,继承了也是抽象方法,集继承之后还是接口,这样可以组合多个接口到一起。
- 组合接口的也许会出现名字冲突,应当尽量避免。
class Hero extends Actioncharacter implements canFight,canSwim,canFly
interface域
接口的任何域都自动是static和final的,所以接口就成为了一种很便捷的用来创建常量组的工具。javaSE5之后,可以使用更加强大的enum关键字定义枚举类型。
接口中的域不能使final空的,不然也没办法修改。会在第一次被加载时就初始化。域不是接口的一部分,它们的值被存储在该接口的静态存储区域内。
工厂设计模式
生成某个接口的对象的典型方式就是工厂方法设计模式,这样会把我们的代码完全与接口分离开来,并且能够隐藏创建对象的具体类,都交由工厂来生产。
//接口
interface Service(){
void method1();
void method2();
}
interface ServiceFactory(){
Service getService();
}
class ImpService1 implements Service{
public void method1(){}
public void method2(){}
}
//厂一
class ImpFactory1 implements ServiceFactory{
return new ImpService1();
}
class ImpService2 implements Service{
public void method1(){}
public void method2(){}
}
//厂二
class ImpFactory2 implements ServiceFactory{
return new ImpService2();
}
//总厂
public class Factorys{
public static void serviceConstumer(ServiceFactory fact){
Service s=fact.getService();
s.method1();
s.method2();
}
}
得到接口对象:
serviceConstumer(new ImpFactory1());
serviceConstumer(new ImpFactory2());
对于创建类,几乎在任何时刻,都可以替代为创建一个接口和一个工厂。因为接口的抽象性不需要具体实现,但是不能滥用接口。任何抽象性都应该是真正的需求产生的。恰当的原则是优先选择类而不是接口。从类开始,如果接口的必需性变得非常明确,那么再进行重构接口。