样例说明

通过本样例,您可以了解:

  1. 什么是能力实例?
  2. 为什么会有多能力实例的场景?
  3. 如何定义多能力实例,并进行调用

环境准备

您需要:

  1. 用于运行程序的IDE(集成开发环境),比如IntelliJ IDEA 或其类似工具;
  2. Java™ Development Kit (JDK),需要JDK 8及以上版本
  3. 已经完成 Quickstart Guide 样例

版本依赖

<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-model</artifactId>
    <version>1.0.15</version>
</dependency>
<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-runtime</artifactId>
    <version>1.0.15</version>
</dependency>

什么是能力实例?

Lattice – 关键概念 – 能力 中,我们介绍了“能力”这个概念。简单说,能力就是对一种特定“功能模式”的抽象。 而针对这些“功能模式”能力抽象的具体实现,就称之为能力实例。

为什么会有多能力实例的场景?

我们以电商交易场景中,在买家下单的过程中,要计算运费、创建物流订单为例。 针对不同的场景有各种各样的物流方案,比如:

  • 传统通过快递进行配送的物流方式(例子中,我们定义 NormalLogisticsAbility)
  • 基于线下门店自提方式进行履约的物流方式。 这种方式,货品发到门店,但交易订单产生后不会有实际物流,用户需要人肉到线下门店去提货。比如,买轮胎,轮胎不是寄到家里,而是自己开车去4S店去安装已购买好的轮胎。 (例子中,我们定义 OfflineLogisticsAbility)
  • 虚拟物品发货方式:比如卡密等商品。。

无论这些物流方式外在的差异有多大,但他们总有一些共性的功能是可以抽象成统一的接口。比如,无论何种运输方式,他都需要计算运费价格、需要在物流订单上保存物流信息等。平台则以面向接口的方式,去调用这些抽象好的接口,最终可实现平台内核稳定,同时也能支持未来新的运输方式的扩展。

如何定义多能力实例,并进行调用

比如,本例中,我们就可以抽象并定义个 “物流能力”,他包含物流运费计算以及物流订单信息补充的抽象接口定义,如下:

@Ability(name = "Logistics ability")
public abstract class LogisticsAbility<T extends IBusinessExt> extends BaseLatticeAbility<T> {

    public LogisticsAbility(OrderLine orderLine) {
        super(orderLine);
    }

    public abstract String getName();

    public abstract long getPostFee();

    public abstract void enrichLogisticsOrderDO(LogisticsOrderDO logisticsOrderDO);
}

那么,针对普通物流和线下门店自提两种方式,我们可以定义两个具体的能力实例:NormalLogisticsAbility 和 OfflineLogisticsAbility。

在普通物流能力实例中,他会去实现 getPostFee() 抽象方法,并进行运费计算。 运费也允许业务开发人员进行扩展,如果没有特殊扩展,就采用一个默认的运费价格。如下:

@Priority(value = 300)
public class NormalLogisticsAbility extends LogisticsAbility<BlankNormalLogisticsExt> {

    private final OrderLine orderLine;

    public NormalLogisticsAbility(OrderLine orderLine) {
        super(orderLine);
        this.orderLine = orderLine;
    }

    @Override
    public String getName() {
        return "Normal";
    }

    @Override
    public boolean supportChecking() {
        String value = orderLine.getAttributes().get("lg_normal");
        return StringUtils.equals(value, "true");
    }

    @Override
    public long getPostFee() {
        Long postFee = reduceExecute(extension -> extension.getCustomPostFee(orderLine),
                Reducers.firstOf(Objects::nonNull));
        return Optional.ofNullable(postFee)
                .map(p -> postFee).orElse(orderLine.getDefaultPostFee());
    }

    ......

}

而线下门店自提的能力实例中,因为他不需要物流配送,运费始终为0,如下:

@Priority(value = 400)
public class OfflineLogisticsAbility extends LogisticsAbility<BlankOfflineLogisticsExt> {

    private final OrderLine orderLine;

    public OfflineLogisticsAbility(OrderLine orderLine) {
        super(orderLine);
        this.orderLine = orderLine;
    }

    @Override
    public String getName() {
        return "Offline";
    }

    @Override
    public long getPostFee() {
        return 0;
    }

    @Override
    public boolean supportChecking() {
        String value = orderLine.getAttributes().get("lg_offline");
        return StringUtils.equals(value, "true");
    }

   ......
}

这两个能力实例中,会有一个 supportChecking() 方法,来校验面对特定的“业务对象”,当前的能力实例是否生效。比如,我们的商品在发布中,往往可以设置多个物流模板。如果,某商品发布时设置了即可以物流配送,也可以到门店自提(比如大闸蟹)。那么用户在下单时,在下单页的物流方式的下拉框中,就可以看到多种方式,可以自行选择。

多能力实例定义完成后,我们在可以通过Lattice中的getAllAbilities和getFirstMatchedAbility两个方法,在运行期筛选出符合条件的能力实例。比如,本例中我们获取可用的运输方式以及该运输方式的运费价格为例,模拟了两次调用。第一次调用,只有普通配送方式,第二次调用追加了线下门店自提的方式。如下:

public class MultiAbilityInstStart {

    public static void main(String[] args) {
        Lattice.getInstance().setSimpleMode(true);
        Lattice.getInstance().start();

        Map<String, String> attributes = Maps.newHashMap();
        attributes.put( "lg_normal", "true"); //只有普通配送方式的能力实例生效
        doInvoke(attributes);
        attributes.put( "lg_offline", "true");//追加线下自提配送方式的能力实例生效
        doInvoke(attributes);
    }

    private static void doInvoke( Map<String, String > attributes){
        System.out.println("--------------------------------------------");
        OrderLine orderLine = new OrderLine();
        orderLine.setUnitPrice(1000L);
        orderLine.setBizCode("cloth");
        orderLine.getAttributes().putAll(attributes);

        List<LogisticsAbility> abilities = Lattice.getAllAbilities(LogisticsAbility.class, orderLine);
        System.out.println("Available Logistic Type: " + abilities.stream().map(LogisticsAbility::getName).collect(Collectors.joining(",")));

        for (LogisticsAbility ability : abilities) {
            Long postFee = ability.getPostFee();
            System.out.println("==>" + ability.getName() + " PostFee:" + postFee);
        }
    }
}

运行结果如下:

--------------------------------------------
Available Logistic Type: Normal
==>Normal PostFee:10000
--------------------------------------------
Available Logistic Type: Normal,Offline
==>Normal PostFee:10000
==>Offline PostFee:0

总结

基于Lattice的多能力实例,可以进一步的对特定的功能模式进行抽象,并且抽象后的模式,也能很方便的进行模式级的扩展。

样例代码可以通过访问:https://github.com/hiforce/lattice-sample/tree/main/lattice-multi-ability-instance 获取