Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

           接口体现了规范与实现分离的设计哲学,面向接口的设计模式也日益深入人心,下面提供了几个完整的例子,演示了接口的优秀设计,并介绍了java常用的两种设计模式:工厂模式和命令模式。

          笔者的开发环境为:java version "1.8.0_40"

 1.

//输出设备接口
public interface OutputSet
{
	//接口的成员变量只能是常量
	int MAT_CACHE=50; //最大缓存
	
	//接口定义的普通方法只能是public的抽象方法
	void out();
	void getData(String msg);
	//在接口中定义默认方法,需要default修饰--需要至少java8的版本支持
	default void print(String...msgs)
	{
		for(String msg : msgs)
			System.out.println(msg);
	}
	//在接口中定义类方法,需要static修饰--需要至少java8的版本支持
	static String type()
	{
		return " 标准输出设备 ";
	}
}

2.

//产品接口
public interface Product
{
	int getProduceTime();
}



3.至此,可以运行下面的类进行测试:

//打印机类  笔者测试环境:java version "1.8.0_40"
public class Printer implements OutputSet,Product
{
	public static void main(String[] args)
	{
	
		OutputSet out=new Printer();
		out.getData("第1张需要打印的文件");
		out.getData("第2张需要打印的文件");
		out.out();
		out.getData("第3张需要打印的文件");
		out.getData("第4张需要打印的文件");
		out.getData("第5张需要打印的文件");
		out.getData(OutputSet.type());
		out.out();
		
	}
	private String[] printData=new String[MAT_CACHE];
	private int printNum=0;
	public void out()
	{
		while(printNum>0)
		{
			System.out.println("打印机打印:"+printData[0]);
			//把作业队列整体前移一位,并将剩下的需要打印数字减1
			/*
			System.arraycopy方法
			public static void arraycopy
								(Object src,int srcPos,Object dest,int destPos, int length)
		    从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
			参数:
				src - 源数组。
				srcPos - 源数组中的起始位置。
				dest - 目标数组。
				destPos - 目标数据中的起始位置。
				length - 要复制的数组元素的数量。 
			*/
			System.arraycopy(printData,1,printData,0,--printNum);
		}
	}
	//重写被实现接口的默认方法
	public void getData(String msg)
	{
		if(printNum>MAT_CACHE)
		{
			System.out.println("输出队列已满,添加失败!");
		}
		else
		{
			printData[printNum++]=msg;
		}
	}
	public int getProduceTime()
	{
		return 10;
	}
}



4.

/*
	面向接口编程--简单工厂模式
	接口体现了规范与实现分离的设计哲学。
*/
//计算机类:需要添加输出设备,已经实现了与Printer类的松耦合,只是与OutputSet接口耦合
public class Computer
{
	private OutputSet out;
	public Computer(OutputSet o)
	{
		out=o;
	}
	//模拟获取输入的方法
	public void keyin(String msg)
	{
		out.getData(msg);
	}
	//模拟打印方法
	public void print()
	{
		out.out();
	}
}



5.至此,可以运行下面的类测试工厂模式:

//工厂类负责生成OutputSet对象
public class OutputSetFactory
{
	public OutputSet getOutputSet()
	{
		//需要为电脑更新设备时,只需要在工厂类里更改方法(改进工艺)即可
		return new Printer();
		//return new BetterPrinter();
	}
	public static void main(String[] args)
	{
		OutputSetFactory of=new OutputSetFactory();
		Computer c=new Computer(of.getOutputSet());
		c.keyin("计算机输入1");
		c.keyin("计算机输入2");
		c.keyin("计算机输入3");
		c.print();
	}
}



6.加入下面的类,只需更改工厂类里的一个方法即可(详见工厂类注释)

//更好的打印机类  笔者测试环境:java version "1.8.0_40"
public class BetterPrinter implements OutputSet,Product
{
	private String[] printData=new String[MAT_CACHE];
	private int printNum=0;
	public void out()
	{
		while(printNum>0)
		{
			System.out.println("更好的打印机打印:"+printData[0]);
			System.arraycopy(printData,1,printData,0,--printNum);
		}
	}
	//重写被实现接口的默认方法
	public void getData(String msg)
	{
		if(printNum>MAT_CACHE)
		{
			System.out.println("输出队列已满,添加失败!");
		}
		else
		{
			printData[printNum++]=msg;
		}
	}
	public int getProduceTime()
	{
		return 10;
	}
}



下面是命令模式

7.

//面向接口编程--简单命令模式
//操作int数组的接口
public interface Command
{
	//封装“处理行为的方法”
	void process(int[] target);
}



8.

//处理数组的处理类
public class ProcessArray
{
	public void process(int[] target,Command cmd)
	{
		cmd.process(target);
	}
}



9.

//打印数组的操作类
public class PrintCommand implements Command
{
    public void process(int[] target)
    {
        for(int tar : target)
            System.out.println("迭代输出目标数组"+tar);
    }

}




10.

//获取数组元素和的操作类
public class AddCommand implements Command
{
    public void process(int[] target)
    {
        int sum=0;
        for(int tar : target)
            sum+=tar;
        System.out.println("数组元素和"+sum);
    }
}



11.至此可以测试命令模式:

//测试类
public class CommandTest
{
    public static void main(String[] args)
    {
        ProcessArray pa=new ProcessArray();
        int[] target={5,0,8,10};
        pa.process(target,new PrintCommand());
        pa.process(target,new AddCommand());
    }
}