【面向对象编程思想】- 接口和抽象类

接口和抽象类的区别

接口 抽象类
是否可以被实例化
是否可以写抽象方法
是否可以写普通方法
是否可以写 static 方法
是否可以写 default 方法
是否可以写属性
访问修饰符 都为 public 可以自定义

为什么需要抽象类

抽象类描述了 is-a 的关系,表示一个类是什么,可以解决代码复用的问题。

典型的场景,通过 “模版方法” 模式,来提高代码复用性。很明显,要想使用 “模版方法” 模式,肯定需要抽象类。
这里举个例子:

/**
 * 抽象的查询执行器类
 */
public abstract class AbstractFindExecutor{
 	public void find(){
        // 1. 拼接查询字段
        buildSelectFields();
        // 2. 拼接查询条件
        buildCriteria();
        // 3. 查询 DB
        doFind();
    }
    
    private String buildSelectFields() {
        return "id, name";
    }

    private String buildCriteria() {
        return "where id = '1q2w3e4r5t'";
    }

    protected abstract String doFind();
}

/**
 * 分页查询的执行类
 */
public class FindPageExecutor extends AbstractFindExecutor {
    /**
     * 这里是分页查询特有的方法
     */
	@Override
    protected String doFind() {
        buildPageable();
        findPageDB();
        return buildResult();
    }

    private String buildPageable() {
        return "limit 30 offset 10";
    }

    private String buildResult() {
        return "success";
    }

    private String findPageDB() {
        return "find page";
    }
}

这个例子中, AbstractFindExecutor 类中的 find 方法描述了一个查询过程。
其中分为三步:

  1. 拼接查询字段
  2. 拼接查询条件
  3. 查询 DB

其中第三步不同的查询方法执行的逻辑是不一样的,比如 “分页查询” 需要构造分页条件和需要组装分页返回数据。

这样子做的目的将查询中公用的方法提取到抽象类的 find 方法中。针对每种查询特有的方法,重写抽象方法实现自身子类特有的方法逻辑。

如果这里没有使用抽象类,那么原本抽象类中的 doFInd() 这个方法不能声明为抽象方法,只能声明一个空方法,且空方法中还需要 throw new UnsupportedOperationException() ,这样的实现不优雅。

为什么不优雅,因为子类没有实现这个空方法,也不会编译报错,不容易在编码的过程中发现问题,其实这又提升了 bug 的出现率。

为什么需要接口

接口描述了 has-a 的关系,表示一个类有某些能力。

使用接口也体现了 “面向接口编程而非实现”。这里体现的思想也就是之前提到的 “抽象”。因为面向接口编程后,就实现了约定和实现相分离,只要约定不变,实现无论怎么改变对调用方不感知,这样也和调用方解耦了,没有强关联。

接口和抽象类如何选择

其实也比较好区别的,因为抽象类描述 is-a 的关系,接口是描述 has-a 的关系

这里再解释一下,is-a 表示 A 类是 B 类的意思。has-a 表示 A 类具有 B 类(可能是个接口)的能力

抽象类是解决代码复用问题
接口是解决拓展问题的

发布了7 篇原创文章 · 获赞 0 · 访问量 55

猜你喜欢

转载自blog.csdn.net/m0_46857718/article/details/105452638