JAVA编程思想(二)如何面向接口编程

Java极客  |  做者  /  铿然一叶
这是Java极客的第 59 篇原创文章

相关阅读:java

JAVA编程思想(一)经过依赖注入增长扩展性
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅知足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
JAVA基础(三)ClassLoader实现热加载
Java并发编程入门(十一)限流场景和Spring限流器实现
HikariPool源码(二)设计思想借鉴
人在职场(一)IT大厂生存法则数据库

1. 接口的本质

接口封装了细节

接口对调用者封装了实现细节,调用者只需按接口规范使用,而不关心怎么实现,例如咱们最多见的数据库链接接口Connection,当经过某个工具包获取Connection后(如HikariPool或者阿里Druid),调用者并不关心实际获取到的是厂家提供的驱动类,仍是被工具包封装以后的代理类。编程

有接口就意味着有变化点

有接口就意味着有变化点,若是没有变化点,也就不须要定义接口,按照固定逻辑实现便可,照此反推,即-有可能发生变化的逻辑,才适合定义接口。例如Java的集合框架,List,Map,Set都有不少不一样实现类,不一样的实现类即是不一样的变化点,能够知足不一样的须要。并发

接口是一套标准

接口是一套标准,例如插座,手机充电口,插入插座的部分并无什么不一样(注意:这里仅说的是插入的部分),从这个角度看接口就是一个标准,只要符合标准就能适配接口,所以并非必定要有变化点才能定义接口,标准的接口是为了更加规范,通用。框架

综上,就是接口的本质,透过这些本质,就很容易知道何时须要定义接口。ide

2. 面向接口编程的优势

从接口的本质实际已经能够看出面向接口编程的优势:工具

A. 接口稳定,易于扩展
B. 替换接口实现时,修改代价小
C. 代码规范,易于维护post

关于接口编程如何易于扩展,请参考:JAVA编程思想(一)经过依赖注入增长扩展性ui

3. 接口调用方式

通常状况下有两种方式:spa

3.1 入参为接口

提供者提供的方法入参或构造器入参定义为接口,由调用者自行肯定实现类,此时调用者要关心接口实现,并可能自行提供最佳实现。

3.2 工厂类生成接口实例

提供者提供的方法中经过工厂类生成接口实例,调用者使用该接口实例,不关心具体实现,例如数据库链接类Connection,一般都是经过工厂类生成给调用者使用。

以上两种调用方式也决定了具体的实现方式。

4. 面向接口编程举例

在接口的本质中已经提到,当要对外屏蔽实现,功能有变化点,或制订标准时须要定义接口,前两个的的例子很常见,就再也不举例,这里仅举例说明接口是如何用于制订标准的。

4.1. 经过接口制订标准例子

注意:

  1. 本例目的仅为说明接口可用于制订标准,进而可采用相同的模式来处理相似逻辑,这样易于后续新开发和维护同类功能,本例并未完整实现。
  2. 另外为了简单,本例都写成了内部类和接口。
import java.util.List;

public class StandardDemo {
    
    public static void main(String[] args) {
        // 在这种场景下,实际使用时必定会引用到实现类,并无屏蔽实现细节,此处接口的做用就是统一标准方法,方便维护。
        DAOInterface<Person, PrimaryKey> dao = new PersonDAO<>();
        
        // 如下代码并无完整实现,仅仅用于示例这个标准接口是如何使用的
        List<Person> people = dao.query(new Condition());
        Person person = dao.queryByPrimaryKey(new PrimaryKey());
        dao.update(new Person());
    }
    
}

// 这个接口的主要目的是:定义一套标准接口方法,要求全部数据库访问都遵循这些标准接口方法来实现,使得统一模式以后更易于维护,而不是各个开发人员各写一套出来。
interface DAOInterface<T, K> {
    List<T> query(Condition condition);
    
    T queryByPrimaryKey(K entiryKey);
    
    int update(T entity);
    
    int create(T entity);
}

class PersonDAO<Person, PrimaryKey> implements DAOInterface<Person, PrimaryKey> {
    @Override
    public List<Person> query(Condition condition) {
        return null; // 仅示例,没有完整实现
    }
    
    @Override
    public Person queryByPrimaryKey(PrimaryKey primaryKey) {
        return null; // 仅示例,没有完整实现
    }
    
    @Override
    public int update(Person entity) {
        return 0; // 仅示例,没有完整实现
    }
    
    @Override
    public int create(Person entity) {
        return 0; // 仅示例,没有完整实现
    }
}

class StudentDAO<Student, PrimaryKey> implements DAOInterface<Student, PrimaryKey> {
    @Override
    public List<Student> query(Condition condition) {
        return null; // 仅示例,没有完整实现
    }
    
    @Override
    public Student queryByPrimaryKey(PrimaryKey primaryKey) {
        return null; // 仅示例,没有完整实现
    }
    
    @Override
    public int update(Student student) {
        return 0; // 仅示例,没有完整实现
    }
    
    @Override
    public int create(Student student) {
        return 0; // 仅示例,没有完整实现
    }
}

// 仅示例,没有完整实现
class Student {
}

// 仅示例,没有完整实现
class Person {
}

// 查询条件类,并未实现
class Condition {
}

// 主键类,并未实现
class PrimaryKey {
}
复制代码

5. 总结:如何面向接口编程

  1. 首先透过接口的本质:是否对外提供接口屏蔽内部实现,是否有变化点,是否要制订标准以方便维护,这三个方面来肯定是否须要定义接口。
  2. 通常来讲要用接口是由于事物既具备共性又有不一样点,要能找到共性又具备不一样点才须要定义接口,例如飞机和鸟都能飞,这是共性,但飞的方式不一样,这是不一样点,这个寻找共性的过程就是抽象的过程,抽象能力高则面向接口编程能力就高。
  3. 接口不是必须的,当拿不定主意是否须要接口时一般有两个可能:“确实不须要接口”“当下你还无法肯定是否须要接口”,这时也没必要勉强,等发现须要时再重构。

end.


<--阅过留痕,左边点赞 !

相关文章
相关标签/搜索