样例说明
通过本样例,您可以了解:
- 什么是能力实例?
- 为什么会有多能力实例的场景?
- 如何定义多能力实例,并进行调用
环境准备
您需要:
- 用于运行程序的IDE(集成开发环境),比如IntelliJ IDEA 或其类似工具;
- Java™ Development Kit (JDK),需要JDK 8及以上版本
- 已经完成 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 获取
2023-09-18 at 下午4:27
多能力实例 与 单能力实例+扩展点 这两种方式的区别是什么?