为什么我们要面向接口编程?!


到底面向?编程

面向过程编程(Procedure Oriented、简称PO面向对象编程(Object Oriented、简称OO 我们一定听过,然而实际企业级开发里受用更多的一种编程思想那就是:面向接口编程(Interface-Oriented

接口这个概念我们一定不陌生,实际生活中最常见的例子就是:插座!

我们只需要事先定义好插座的接口标准,各大插座厂商只要按这个接口标准生产,管你什么牌子、内部什么电路结构,这些均和用户无关,用户拿来就可以用;而且即使插座坏了,只要换一个符合接口标准的新插座,一切照样工作!

同理,实际代码设计也是这样!

我们在设计一个软件的代码架构时,我们都希望事先约定好各个功能的接口(即:约定好接口签名和方法),实际开发时我们只需要实现这个接口就能完成具体的功能!后续即使项目变化、功能升级,程序员只需要按照接口约定重新实现一下,就可以达到系统升级和扩展的目的!

正好,Java中天生就有interface这个语法,这简直是为面向接口编程而生的!

所以接下来落实到代码上,举个通俗一点的小例子唠一唠,实际业务代码虽然比这个复杂,但原理是一模一样的。


做梦了

假如哪一天程序羊真发达了,一口豪气买了两辆豪车,一辆五菱宏光、一辆飞度、并且还专门聘请了一位驾驶员来帮助驾驶。

两辆豪车在此:

public class Wuling {    public void drive() {        System.out.println("驾驶五菱宏光汽车");    }}public class Fit {    public void drive() {        System.out.println("驾驶飞度汽车");    }}复制代码

驾驶员定义在此:

驾驶员定义了两个drive()方法,分别用来驾驶两辆车:

public class Driver {    public void drive( Wuling wuling ) {        wuling.drive(); // 驾驶五菱宏光的方法    }        public void drive( Fit fit ) {        fit.drive();    // 驾驶飞度的方法    }    // 用于测试功能的 main()函数    public static void main( String[] args ) {            // 实例化两辆新车        Wuling wuling = new Wuling();        Fit fit = new Fit();                // 实例化驾驶员        Driver driver = new Driver();                driver.drive( wuling ); // 帮我开五菱宏光        driver.drive( fit );    // 帮我开飞度    }}复制代码

这暂且看起来没问题!日子过得很融洽。

但后来过了段时间,程序羊又变得发达了一点,这次他又豪气地买了一辆新款奥拓(Alto)!

可是现有的驾驶员类Driver的两个drive()方法里都开不了这辆新买的奥拓该怎么办呢?


代码的灵活解耦

这时候,我想应该没有谁会专门再去往Driver类中添加一个新的drive()方法来达到目的吧?毕竟谁也不知道以后他还会不会买新车!

这时候如果我希望我聘请的这位驾驶员对于所有车型都能驾驭,该怎么办呢?

很容易想到,我们应该做一层抽象。毕竟不管是奥拓还是奥迪,它们都是汽车,因此我们定义一个父类叫做汽车类Car,里面只声明一个通用的drive()方法,具体怎么开先不用管:

// 抽象的汽车类Car,代表所有汽车public class Car {    void drive() { } // 通用的汽车驾驶方法}复制代码

这时,只要我新买的奥拓符合Car定义的驾驶标准即可被我的驾驶员驾驶,所以只需要新的奥拓来继承一下Car类即可:

public class Alto extends Car {    public void drive() {        System.out.println("驾驶奥拓汽车");    }}复制代码

同理,只需要我的驾驶员具备通用汽车Car的驾驶能力,那驾驶所有的汽车都不是问题,因此Drvier类的drive()方法只要传入的参数是父类,那就具备了通用性:

public class Driver {    public void drive( Car car ) {  // 方法参数使用父类来替代        car.drive();    }    public static void main( String[] args ) {        Alto alto = new Alto();        Driver driver = new Driver();        driver.drive( alto );    }}复制代码

问题暂且解决了!


但是再后来,程序羊他好像又更发达了一些,连车都不想坐了,想买一头驴(Donkey)让司机骑着带他出行!

很明显,原先适用于汽车的drive()方法肯定是不适合骑驴的!但我们希望聘请的这位驾驶员既会开汽车,又会骑驴怎么办呢?

害!我们干脆直接定义一个叫做交通工具(TrafficTools)的通用接口吧!里面包含一个通用的交通工具使用方法,管你是驾驶汽车,还是骑驴骑马,具体技能怎么实现先不管:

// 通用的交通工具接口定义public interface TrafficTools {    void drive();  // 通用的交通工具使用方法}复制代码

有了这个接口约定,接下来就好办了。我们让所有的Car、或者驴、马等,都来实现这个接口:

public class Car implements TrafficTools {    @Override    public void drive() { }}public class Wuling extends Car {    public void drive() {        System.out.println("驾驶五菱宏光汽车");    }}public class Fit extends Car {    public void drive() {        System.out.println("驾驶飞度汽车");    }}public class Alto extends Car {    public void drive() {        System.out.println("驾驶奥拓汽车");    }}public class Donkey implements TrafficTools {    @Override    public void drive() {        System.out.println("骑一头驴");    }}复制代码

这个时候只要我们的驾驶员师傅也面向接口编程,就没有任何问题:

public class Driver {    // 方法参数面向接口编程    public void drive( TrafficTools trafficTools ) {        trafficTools.drive();    }    public static void main( String[] args ) {        Driver driver = new Driver();        driver.drive( new Wuling() );  // 开五菱        driver.drive( new Fit() );     // 开飞度        driver.drive( new Alto() );    // 开奥拓        driver.drive( new Donkey() );  // 骑一头驴    }}复制代码

很明显,代码完全解耦了!这就是接口带来的便利。


代码的扩展性

面向接口编程的优点远不止上面这种代码解耦的场景,在实际企业开发里,利用接口思想对已有代码进行灵活扩展也特别常见。

再举一个例子:假设程序羊有一个非常豪气的朋友,叫:程序牛,他们家出行可不坐车,全靠私人飞机出行:

// 通用的飞机飞行接口public interface Plane {    void fly();}// 程序牛的专用机长,受过专业训练(即:实现了通用飞行接口)public class PlaneDriver implements Plane {    @Override    public void fly() {        System.out.println("专业的飞行员操控飞机");    }}// 出门旅行public class Travel {    // 此处函数参数也是面向接口编程!!!    public void fly( Plane plane ) {        plane.fly();    }    public static void main( String[] args ) {        Travel travel = new Travel();  // 开启一段旅行        PlaneDriver planeDriver = new PlaneDriver(); // 聘请一个机长        travel.fly( planeDriver ); // 由专业机长开飞机愉快的出去旅行    }}复制代码

但是突然有一天,他们家聘请的机长跳槽了,这时候程序牛一家就无法出行了,毕竟飞机不会驾驶。

于是他跑来问我借司机,想让我的驾驶员来帮他驾驶飞机出去旅行。

我一看,由于他们的代码面向的是接口,我就肯定地答应了他!

这时候对我这边的扩展来说就非常容易了,我只需要安排我的驾驶员去培训一下飞行技能就OK了(实现一个方法就行):

// 让我的驾驶员去培训一下飞行技能(即:去实现通用飞行接口)public class Driver implements Plane {    public void drive( TrafficTools trafficTools ) {        trafficTools.drive();    }        // 实现了fly()方法,这下我的驾驶员也具备操控飞机的能力了!    @Override    public void fly() {        System.out.println("普通驾驶员操控飞机");    }}复制代码

这时候我的驾驶员Driver类就可以直接服务于他们一家的出行了:

public class Travel {    public void fly( Plane plane ) {        plane.fly();    }    public static void main( String[] args ) {        Travel travel = new Travel();        // 专业飞行员操控飞机        PlaneDriver planeDriver = new PlaneDriver();        travel.fly( planeDriver );        // 普通驾驶员操控飞机        Driver driver = new Driver();        travel.fly( driver );    }}复制代码

看到没,这一改造过程中,我们只增加了代码,却并没有修改任何已有代码,就完成了代码扩展的任务,非常符合开闭原则


实际项目

实际开发中,我们就暂且不说诸如Spring这种框架内部会大量使用接口,并对外提供使用,就连我们自己平时写业务代码,我们也习惯于在Service层使用接口来进行一层隔离:

这种接口定义和具体实现逻辑的分开,非常有利于后续扩展和维护!


小结

面向接口编程开发,对代码架构的解耦和扩展确实很有好处,这种编码思想也值得平时开发结合实践反复理解和回味!

(0)

相关推荐

  • 面向对象的六大原则之 接口隔离原则——ISP

    ISP = Interface Segregation Principle   ISP的定义如下: 1.客户端不应该依赖他不需要的接口 2.一个类对另外一个类的依赖性应该是建立在最小的接口上 3.不应 ...

  • 一文介绍Java编程思想--接口

    编程人员是最勤快的人,也是最懒惰的一群人,总是不断地学习,能够自动完成的绝对不会手写.要成为合格的Java全栈工程师?请完全理解Java的编程思想! 接口 interface关键字使抽象的概念更向前迈 ...

  • C语言实现面向接口编程

    今天更新的文章,我相信是大伙喜欢的,来聊聊面向接口编程. 不是一直都吹嘘着面向对象编程吗?怎么今天又来一个面向接口编程,很多人要说我不讲武德了. 1 面向接口是啥? 不用慌,其实面向接口编程不是什么新 ...

  • Python 中的面向接口编程

    "面向接口编程"写 Java 的朋友耳朵已经可以听出干茧了吧,当然这个思想在 Java 中非常重要,甚至几乎所有的编程语言都需要,毕竟程序具有良好的扩展性.维护性谁都不能拒绝. 最 ...

  • 面向接口/协议?看DuerOS的技能开发

    一般地,开发一个对话系统或者机器人问答系统会涉及诸多领域的技术,除了硬件系统之外,还包括语言识别,自然语言处理/识别,知识图谱的搭建,自然语言生成及TTS播报等等,这对于企业及开发者个人而言,几乎是难 ...

  • 以后再也不用面向Google编程了

    2021-07-01 09:51·技术联盟总坛 码农翻身刘欣 码农翻身 编程中遇到问题,Google一下, 复制.粘贴.调试...... 估计很多人都有这样的经历吧. 今天看到一个VS Code的插件 ...

  • Stata的面向函数式编程——以独董职业背景多元化赫芬达尔指数的计算过程为例

    众所周知,在学习python的时候,老师们一般喜欢将编程的思维分成面向过程.面向函数和面向对象式编程几种,学习的过程层层递进.在使用stata的时候,我们一般都喜欢面向过程式编程,这也是stata经常 ...

  • (50条消息) 面向 Kubernetes 编程: Kubernetes 是下一代操作系统

    此文章适合没有任何 Kubernetes/容器/Docker 经验的同学 -- 在不久的将来,你不懂如何操作 Kubernetes 接口,就等于现在的你不懂最普通的 Linux 命令.导言 此文章着重 ...

  • 请不要面向监狱编程

    导语:上篇文章不是说了句爬虫没烦恼,牢饭少不了嘛,然后就引起了我的好奇心,加上之前老是看到程序员靠技术吃牢饭的新闻,所以有了这篇文章,理性看待请勿上头. 平时上网冲浪的时候,总是觉得网上别家程序猿们的 ...

  • 工业相机编程流程及SDK接口使用汇总

    内容纲要: 1.工业相机编程模型和流程 2.工业相机SDK接口使用总结 3.Basler Pylon工业相机SDK的使用 4.Pylon 以实时图像采集讲解PylonC SDK使用流程 5.关于使用维 ...