深入理解面向接口编程(那些年的面向接口编程,DIY电脑为例)
面向接口编程(哪些年的面向接口编程)
接口是Java的重要特性之一,在Java8以前,接口可以说是一种方法签名,或者一种行为契约,类实现了某个接口,就需要实现该接口中定义的方法。接口可以认为是一种特殊的抽象类,Java8之前的版本在接口中只能定义常量和抽象方法。实现类实现接口本身也类似于继承,只是继承过来的是行为约束,比如:人打从娘胎里出来就约定了必须具有的行为:吃喝拉撒。Java的接口本身依托于Java的多态机制,以下通过一个列子,说明面向接口编程为何能够提升我们代码的灵活性、可扩展性,并且有效降低代码的耦合。
1.首先还是简单地介绍下接口的定义(Java8之前的版本,在此不讨论Java8新的default特性)
Java8以前接口的定义如下:
[访问权限] interface 接口名 {
公开的静态常量列表;
公开的抽象方法列表;
}
类实现接口:
[访问权限] class 类名称 implements 接口1,接口2{
//重写接口1中的方法
//重写接口2中的方法
}
2.学IT行业的同学,尤其是爱打游戏的同学,可能自己组装过电脑,下面通过组装电脑为例,简要地理解面向接口编程的好处
我们都知道现在的电脑主板上提供了很多接口,CPU插口、硬盘插口、内存插口、显卡插口,同一块主板上各类接口,一般都同时支持多种类型的CPU、硬盘和内存和显卡,假如有如下场景:
小哥哥是个游戏高手,手头不太富裕,花了8000块钱配置了一台电脑:
技嘉的主板型号1、I7CPU、512G SSD、8G内存、2G独显
通过半年的省吃俭用,小哥哥终于攒了1万块钱,购买了一块5000块钱的超级显卡,对电脑升级。
试想如果电脑显卡、内存、CPU、硬盘等都是不可插拔的,而是焊接死的,求小哥哥的心理阴影面积。
好下面我们通过组装电脑为例说明面向接口编程的灵活之处,假设电脑只有CPU和硬盘:
定义CPU接口:
/**
* 定义CPU接口
* @author liuhaibing
* @version 1.0
*/
public interface CPU {
// 面向接口编程:接口其实可以认为是一个标准,一个行为契约
// 接口的方法默认就是public abstract的
void calculate(); // CPU要能计算
}
定义硬盘接口:
/**
* 定义硬盘接口
* @author liuhaibing
* @version 1.0
*/
public interface Disk {
void storeData(); // 硬盘要能存储数据
}
定义I3CPU类实现了CPU接口:
/**
* @author liuhaibing
* @version 1.0
*/
public class I3CPU implements CPU{
private double rate = 2.6;
@Override
public void calculate() {
// TODO Auto-generated method stub
System.out.println("我是i3的CPU I'm running!");
}
}
定义I7CPU类实现了CPU接口:
/**
* @author liuhaibing
* @version 1.0
*/
public class I7CPU implements CPU{
@Override
public void calculate() {
// TODO Auto-generated method stub
System.out.println("我是i7的CPU I'm running!");
}
}
定义NormalDisk(机械硬盘了)并实现Disk接口:
/**
* @author liuhaibing
* @version 1.0
*/
public class NormalDisk implements Disk{
@Override
public void storeData() {
// TODO Auto-generated method stub
System.out.println("我是机械硬盘 I'm running!");
}
}
定义SSDDisk(固态硬盘类)并实现Disk接口:
/**
* @author liuhaibing
* @version 1.0
*/
public class SSDDisk implements Disk{
@Override
public void storeData() {
// TODO Auto-generated method stub
System.out.println("我是固态硬盘 I'm running!");
}
}
定义电脑类:
/**
* @author liuhaibing
* @version 1.0
*/
public class Computer {
// 在这里定义的是接口,不是具体的实现类,所以就达到了面向接口编程的目的,这样电脑不
// 直接依赖具体的硬盘或CPU的实现
private Disk disk; // 硬盘插口 computer关联了disk和cpu
private Disk disk2; // 硬盘插口2
private CPU cpu; // CPU插口
// 以**释的定义代是非面向接口编程,电脑和具体的硬盘绑定了,构成了强耦合
// private I7CPU cpu;
// private SSDDisk disk; 耦合
// 标准面向接口编程的构造方法,组装的时候使用接口作为电脑类构造方法的形参,从而达到解耦合
public Computer(Disk disk, CPU cpu, Disk disk2) {
this.disk = disk;
this.cpu = cpu;
this.disk2 = disk2;
}
// 如果不用面向接口编程,组装不同的电脑要不同的构造方法,类似就像是为新开一条生产线
// 代码也和具体的实现类产生了耦合
//public Computer(SSDDisk disk, I3CPU cpu, NormalDisk disk2) {
//}
// 如果不用面向接口编程,组装不同的电脑要不同的构造方法,类似就像是为新开第二条生产线
//public Computer(SSDDisk disk, I7CPU cpu, Disk disk2) {
//}
// 启动电脑
public void startComputer() {
if(disk != null && cpu !=null) {
cpu.calculate();
disk.storeData();
}else {
System.out.println("启动失败");
}
}
}
下面开始组装不同的电脑:
/**
* @author liuhaibing
* @version 1.0
*/
public class DiyComputer{
/**
* @author liuhaibing
* @version 1.0
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// 第一台电脑的配置
Disk disk = new SSDDisk(); //多态:接口的引用引用了实现类的对象
CPU cpu = new I3CPU();
// diy第一台电脑
Computer cp = new Computer(disk, cpu, null);
cp.startComputer();
// 第二台电脑的配置
Disk disk2 = new SSDDisk();
CPU cpu2 = new I7CPU();
// diy第二台电脑
Computer cp2 = new Computer(disk2, cpu2, null);
cp2.startComputer();
}
}