前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 接口的所有子类都需要执行相同处理逻辑的推荐姿势

Java 接口的所有子类都需要执行相同处理逻辑的推荐姿势

作者头像
明明如月学长
发布2021-12-02 08:06:47
8640
发布2021-12-02 08:06:47
举报

一、背景

在实际开发过程中,有些时候我们可能会遇到这样的场景:我们定义接口给上游使用,不同的业务类型定义不同的子类型,实现该接口的某个函数,但是这些子类型会有很多公共的逻辑(公共的步骤)。

如果将这部分代码定义为工具方法,就需要在每个子类中都执行对应的调用。

如果有些公共步骤的返回值和接口中定义的返回值一致时,很容易出现漏调用的情况。

那么,该如何 “强制”子类型都要执行一些相同的步骤呢?

二、描述

下面都是伪代码,大家不必纠结于具体细节,理解意思即可。

我们需要提供给上游这样一个接口, type 是指当前服务能够处理的类型,something 代表实际执行的业务功能。

代码语言:javascript
复制
public interface SomeInterface {

    String type();
    
    ResultDTO something(Param param);
}

第一个实现类:

代码语言:javascript
复制
public class AImpl implements SomeInterface {

	@Override
    public String type() {
        return "A";
    }
    
    @Override
    public ResultDTO something(Param param) {
        // 特有逻辑
        ResultDTO resultDTO = buildPart(param);

        // 构造公共逻辑所需的参数
        OtherParam otherParam = new OtherParam();

        // 公有逻辑
        return SomeUtils.fillCommon(resultDTO, otherParam);
    }

    private ResultDTO buildPart(Param param) {
        ResultDTO result = new ResultDTO();
        // 执行查询

        // 塞入特有属性

        return result;
    }
}

第二个实现类:

代码语言:javascript
复制
public class BImpl implements SomeInterface {

	@Override
    public String type() {
        return "B";
    }
    
    @Override
    public ResultDTO something(Param param) {
        // 特有逻辑
        ResultDTO resultDTO = buildPart(param);

        // 构造公共逻辑所需的参数
        OtherParam otherParam = new OtherParam();

        // 公有逻辑
        return SomeUtils.fillCommon(resultDTO, otherParam);
    }

    private ResultDTO buildPart(Param param) {
        ResultDTO result = new ResultDTO();
        // 执行查询

        // 塞入特有属性

        return result;
    }

}

使用时,构造 Map type2BeanMap ,然后根据当前的 type 去执行具体的实现 Bean。

具体可参考《巧用 Spring 自动注入实现策略模式升级版》

问题:如果我们新增 CImpl 继承 SomeInterface 就必须查看 AImpl 或者 BImpl 源码才知道有一段公共逻辑,很容易遗漏这一段公共逻辑。

如果我们想让新建子类时,不需要担心遗漏这段公共的逻辑,该怎么办?

三、方案

如果大家对设计模式比较熟悉的话,这种场景我们很自然地会联想到模板模式

我们将采用这种设计模式,对代码进行改造。

(1)我们将特有逻辑上提到接口中,在 default 方法中编排逻辑即可。

代码语言:javascript
复制
public interface SomeInterface {

    String type();

    // 目标方法
    default ResultDTO something(Param param) {
        return SomeUtils.fillCommon(buildPart(param));
    }

    /**
     * 特有逻辑
     */
    MiddleParam buildPart(Param param);
}

定义为接口的好处是,不会影响到子类继承其他父类型(Java 是单继承机制)。

(2)可以将 SomeInterface 改为抽象类(AbstractSomeService),something定义为 public ,将 builPart 定义为抽象函数,让子类去重写。

代码语言:javascript
复制
public abstract class AbstractSomeService {

    abstract String type();

    // 目标方法
    public ResultDTO something(Param param) {
        return SomeUtils.fillCommon(buildPart(param));
    }

    /**
     * 特有逻辑
     */
    abstract MiddleParam buildPart(Param param);
}

定义为抽象类的坏处是子类型无法再继承其他类,但理论上也不应该(不需要) 再继承其他类。

注意: (1) 本案例里的 SomeUtils.fillCommon 只是伪代码,公共逻辑可能封装在工具类中,也可能封装在某个 bean 中,在抽象类或者接口中可以通过ApplicationContextHolder 去获取并调用。 (2) 实际编码时,公共逻辑也未必在最后调用。 (3) 实际编码中,公共的步骤可能不止一个,但是方案是一致的,有几个定义几个抽象方法即可。 (4)实际编码时,公共的步骤可能不需要返回值

定义中间参数:

代码语言:javascript
复制
@Data
public class MiddleParam {

    private ResultDTO semiResult;

    private OtherParam otherParam;
}

第一个实现类:

代码语言:javascript
复制
public class AImpl extends AbstractSomeService {
    @Override
    public String type() {
        return "A";
    }


    @Override
    public MiddleParam buildPart(Param param) {
        MiddleParam middleParam = new MiddleParam();
        // 执行查询

        // 塞入特有属性

        return middleParam;
    }
}

第二个实现类:

代码语言:javascript
复制
public class BImpl extends AbstractSomeService {

    @Override
    public String type() {
        return "B";
    }

    @Override
    public MiddleParam buildPart(Param param) {
        MiddleParam middleParam = new MiddleParam();
        // 执行查询

        // 塞入特有属性

        return middleParam;
    }

}

这样通过类似 buildPart 这种函数名,可以明确感知到当前是对部分逻辑进行处理,且不需要在当前子类中执行公共逻辑的调用。

四、总结

本文案例比较简单,主要思想是使用模板模式来实现公共步骤的编排。

希望大家遇到类似场景时,可以使用更优雅的方式,更健壮的方式去实现,而不是依靠“口口相传” 或者让别人看你代码才知道该怎么写。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-12-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、描述
  • 三、方案
  • 四、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com