1.接口的定义
1.1.接口的基本定义
1 interface IClassName{ 2 public String getClassName(); 3 } 4 class Company implements IClassName{ 5 public String getClassName() { 6 return "classname"; 7 } 8 } 9 public class interface_01 { 10 public static void main(String[] args) { 11 IClassName comp = new Company(); 12 System.out.println(comp.getClassName()); 13 } 14 }
1.2.接口的继承
1.MessageImpl子类的对象可以任意的实现父接口的转换。
2.Object类对象可以接收所有的数据类型,包括基本数据类型、类对象、接口对象、数组。
3.由于接口描述的是一个公共的定义标准,所以在接口中所有的抽象方法的访问全县都为public,所以写与不写都是一样的。
注意:
1.接口中的方法不写访问权限也是public,不是default,所以覆写的时候只能够使用public。 2.接口中的抽象方法abstract写于不写都一样。 在实际开发过程中,实现接口的又可能是抽象类,一个抽象类可以实现多个接口。 3.一个普通类只能够继承一个抽象类并且可以实现多个父接口,但是要求先继承后实现。
1 interface IMessage{ 2 public static final String INFO="www.sina.com.cn";//全局常量 3 public abstract String getInfo();//抽象方法 4 //3.由于接口描述的是一个公共的定义标准,所以在接口中所有的抽象方法的访问全县都为public,所以写与不写都是一样的。 5 //String INFO="www.sina.com.cn";//方法不写访问权限也是public,不是default,所以覆写的时候只能够使用public。 6 //String getInfo();//abstract写于不写都一样。 在实际开发过程中,实现接口的又可能是抽象类,一个抽象类可以实现多个接口, 7 //一个普通类只能够继承一个抽象类并且可以实现多个父接口,但是要求先继承后实现。 8 } 9 abstract class DatabaseAbstract{ 10 public abstract boolean getDatabaseAbstract(); 11 } 12 interface IChannel{ 13 public abstract boolean connect(); 14 } 15 class MessageImpl extends DatabaseAbstract implements IMessage, IChannel{//一个子类可以实现多个接口 16 public String getInfo() { 17 if(this.connect()) { 18 if(this.getDatabaseAbstract()) { 19 return "数据库得到一个消息:房价又跌了!"; 20 }else { 21 return "数据库消息无法访问!"; 22 } 23 } 24 return "通道建立失败!"; 25 } 26 public boolean connect() { 27 System.out.println("通道建立成功!"); 28 return true; 29 } 30 public boolean getDatabaseAbstract() { 31 return true; 32 } 33 } 34 public class interface_02 { 35 public static void main(String[] args) { 36 IMessage msg = new MessageImpl(); 37 System.out.println(msg.getInfo()); 38 //System.out.println(IMessage.INFO); 39 40 //IChannel chnl = (IChannel) msg; //1.MessageImpl子类的对象可以任意的实现父接口的转换。 41 //System.out.println(chnl.connect()); 42 43 //Object obj = msg; 44 //IChannel chan = (IChannel)obj; 45 //System.out.println(chan.connect());//2.Object类对象可以接收所有的数据类型,包括基本数据类型、类对象、接口对象、数组。 46 } 47 }
1.3.接口的多继承
需要覆写接口中的所有抽象方法:包括本接口中的方法和继承的所有方法。
1 interface IMessage{ 2 public abstract String getInfo(); 3 } 4 interface IChannel{ 5 public boolean connect(); 6 } 7 //extends在类继承上只能够继承一个父类,但是接口上可以继承多个父接口。 8 interface IService extends IMessage, IChannel{//接口多继承 9 public String service(); 10 } 11 class MessageService implements IService{ 12 public String getInfo() { 13 return ""; 14 } 15 public boolean connect() { 16 return true; 17 } 18 public String service() { 19 return "获取消息服务。"; 20 } 21 } 22 public class interface_03 { 23 public static void main(String[] args) { 24 MessageService msg = new MessageService(); 25 System.out.println(msg.service()); 26 } 27 }
在实际的开发中,接口的使用往往有三种形式:
1.进行标准设置;
2.表示一种操作的能力;
3.暴露远程方法试图,这个一般都在RPC分布式开发中使用。
1.4.接口定义加强
接口最早的主要特点是全部由抽象方法和全局变量所组成,但是如果你的项目设计不当,就有可能出现一种非常严重的问题。
自从JDK1.8之后开始,为了解决接口设计的缺陷,在接口中允许开发者使用default定义普通方法。
1 interface IMessage{ 2 public String message(); 3 public default boolean connect() { 4 System.out.println("建立消息的连接通道。"); 5 return true; 6 } 7 } 8 class MessageImpl implements IMessage{ 9 public String message() { 10 return "www.sina.com.cn"; 11 } 12 } 13 public class interface_04 { 14 public static void main(String[] args) { 15 IMessage msg = new MessageImpl(); 16 System.out.println(msg.connect()); 17 } 18 }
接口中的普通方法必须追加default声明,但是需要提醒的是,该操作属于挽救功能,所以如果不是必须的情况下,不应该作为设计的首选。
除了可以追加普通方法之外,接口里面也可以定义static方法,而static方法就可以通过接口直接调用。
举例:在接口中定义static方法
1 interface IMessage{ 2 public String message(); 3 public default boolean connect() { 4 System.out.println("建立消息的连接通道。"); 5 return true; 6 } 7 public static IMessage getInstance() { 8 return new MessageImpl(); 9 } 10 } 11 class MessageImpl implements IMessage{ 12 public String message() { 13 if(this.connect()) { 14 return "www.sina.com.cn"; 15 } 16 return "消息没有发送!"; 17 } 18 } 19 public class interface_04 { 20 public static void main(String[] args) { 21 IMessage msg = IMessage.getInstance(); 22 System.out.println(msg.connect()); 23 } 24 }
如果现在真的可以在接口里面定义普通方法或者static方法,那么这个功能就已经可以取代抽象类了,但是不应该将这两个组成作为接口的主要设计原则。我们缩写的代码里面还是应该奉行:接口就是抽象方法。
1.5.使用接口定义标准
对于接口而言,在开发制作最为重要的应用就是进行标准的制定,实际上在日常的生活中也会听到许多关于接口的名词,例如USB接口、PCI接口、鼠标接口等,那么这些实际上都是属于标准的应用。
电脑上可以插入各种USB的设备,所以电脑上认的是USB标准,而不关心这个标准的具体实现类。
举个例子:
1 interface IUSB{ 2 public boolean check(); 3 public void work(); 4 } 5 class Computer{ 6 public void plugin(IUSB usb) { 7 if(usb.check()) { 8 usb.work(); 9 }else { 10 System.out.println("硬件设备安装出现问题!"); 11 } 12 } 13 } 14 class Keyboard implements IUSB{ 15 public boolean check() { 16 return true; 17 } 18 public void work() { 19 System.out.println("开始进行码字任务。"); 20 } 21 } 22 class Printer implements IUSB{ 23 public boolean check() { 24 return false; 25 } 26 public void work() { 27 System.out.println("开始进行照片打印。"); 28 } 29 } 30 public class interface_05 { 31 public static void main(String[] args) { 32 Computer computer = new Computer(); 33 computer.plugin(new Keyboard()); 34 computer.plugin(new Printer()); 35 } 36 }
1.6.工厂设计模式
对于接口而言,已经可以明确的是,必须有子类,而且子类可以通过对象的向上转型来获取接口的实例化对象。但是在进行对象实例化的过程中,也有可能存在设计问题。
举个例子:
1 interface IFood{ 2 public void eat(); 3 } 4 class Bread implements IFood{ 5 public void eat() { 6 System.out.println("吃面包。"); 7 } 8 } 9 public class interface_06 { 10 public static void main(String[] args) { 11 IFood food = new Bread(); 12 food.eat(); 13 } 14 }
在本程序中根据接口定义来子类的定义,并且利用对象的向上转型进行接口对象实例化处理。
现在出现了问题:客户端需要明确的知道具体的哪一个子类,如果现在面包吃腻了,需要牛奶了,那么客户端就要作出相应的修改。
1 interface IFood{ 2 public void eat(); 3 } 4 class Bread implements IFood{ 5 public void eat() { 6 System.out.println("吃面包。"); 7 } 8 } 9 class Milk implements IFood{ 10 public void eat() { 11 System.out.println("喝牛奶。"); 12 } 13 } 14 public class interface_06 { 15 public static void main(String[] args) { 16 IFood food = new Milk(); 17 food.eat(); 18 } 19 }
所以,此时的程序就出现了耦合的问题,而造成耦合最直接的元凶是“关键字new”。
以Java的设计为例,Java实现可移植性的关键是JVM,而JVM的核心原理:利用一个虚拟机来运行Java程序,所有的程序并不与具体的操作系统有任何关联,而是由JVM来进行匹配。所以得出结论:良好的设计应该避免耦合。
举个例子:
1 interface IFood{ 2 public void eat(); 3 } 4 class Bread implements IFood{ 5 public void eat() { 6 System.out.println("吃面包。"); 7 } 8 } 9 class Milk implements IFood{ 10 public void eat() { 11 System.out.println("喝牛奶。"); 12 } 13 } 14 class Factory{ 15 public static IFood getInstance(String className) { 16 if("bread".equals(className)) { 17 return new Bread(); 18 }else if("milk".equals(className)) { 19 return new Milk(); 20 }else { 21 return null; 22 } 23 } 24 } 25 public class interface_06 { 26 public static void main(String[] args) { 27 IFood food = Factory.getInstance(args[0]); 28 food.eat(); 29 } 30 }
在本程序中,客户端程序类与IFood接口的子类没有任何的关联,所有的关联都是通过Factory类来完成的,而在程序运行的时候可以通过初始化参数进行要使用的子类定义,如果日后需要进行子类扩充的时候,只需要修改Factory类即可实现。使用工厂模式完全隐藏了实现的子类。
1.7.代理设计模式
代理设计模式的主要功能,是可以帮助用户将所有的开发注意力只集中在核心业务功能的处理上。
例如:肚子饿了,如何可以吃到食物。
1 interface IEat{ 2 public void get(); 3 } 4 class EatReal implements IEat{ 5 public void get() { 6 System.out.println("【真实主题】得到一份食物,然后开始品尝美食。"); 7 } 8 } 9 class EatProxy implements IEat{//服务代理 10 private IEat eat;//为吃服务 11 public EatProxy(IEat eat) {//一定要有一个代理项 12 this.eat = eat; 13 } 14 public void get() { 15 this.prepare(); 16 this.eat.get(); 17 this.clean(); 18 } 19 public void prepare() {//准备过程 20 System.out.println("【代理主题】1、精心购买食材。"); 21 System.out.println("【代理主题】2、小心的处理食材。"); 22 } 23 public void clean() { 24 System.out.println("【代理主题】3、收拾碗筷。"); 25 } 26 } 27 public class interface_07 { 28 public static void main(String[] args) { 29 IEat eat = new EatProxy(new EatReal()); 30 eat.get(); 31 } 32 }
代理接口设计模式的主要特点是:一个接口提供两个子类,其中一个子类是真实业务操作类,另外一个子类是代理业务操作类。没有代理业务操作,真实业务无法执行。
工厂模式例子:
定义类Shape,用来表示一般二维图形。Shape具有抽象方法area()和perimeter(),分别用来计算形状的面积和周长。试定义一些形状类(如矩形、三角形、圆形、椭圆形等),这些类均为Shape类的子类。
1 abstract class AbsShape{ 2 public abstract double area(); 3 public abstract double perimeter(); 4 } 5 class Circular extends AbsShape{ 6 private double radius; 7 public Circular(double radius) { 8 this.radius = radius; 9 } 10 public double area() { 11 return Math.PI * radius * radius; 12 } 13 public double perimeter() { 14 return 2 * Math.PI * radius; 15 } 16 } 17 class Triangle extends AbsShape{ 18 private double length; 19 private double width; 20 public Triangle(double length,double width) { 21 this.length = length; 22 this.width = width; 23 } 24 public double area() { 25 return this.length * this.width; 26 } 27 public double perimeter() { 28 return 2 * (this.length + this.width); 29 } 30 } 31 class Factory_a{ 32 public static AbsShape getInstance(String className, double... args) { 33 if("Circular".equalsIgnoreCase(className)) { 34 return new Circular(args[0]); 35 }else if("Triangle".equalsIgnoreCase(className)) { 36 return new Triangle(args[0], args[1]); 37 }else { 38 return null; 39 } 40 } 41 } 42 public class 计算面积 { 43 public static void main(String[] args) { 44 AbsShape asa = Factory_a.getInstance("circular", 3.0); 45 AbsShape asb = Factory_a.getInstance("triangle", 2.0, 1.5); 46 System.out.println("圆的面积:"+ asa.area() + ",圆的周长:" + asa.perimeter()); 47 System.out.println("矩形的面积:"+ asb.area() + ",矩形的周长:" + asb.perimeter()); 48 } 49 }
运行结果:
圆的面积:28.274333882308138,圆的周长:18.84955592153876
矩形的面积:3.0,矩形的周长:7.0