写点什么

Lattice - 模式级复用的能力定义

作者:毗卢道场
  • 2023-01-29
    江苏
  • 本文字数:5080 字

    阅读完需:约 17 分钟

Lattice - 模式级复用的能力定义

1、概念介绍:能力

在 Lattice 框架里,有一个叫做“能力(Ability)”的名词。 这里,我就这个名词做下我的理解。


《吕氏春秋·适威》:“民进则欲其赏,退则畏其罪,知其能力之不足也!”


方纪 《三峡之秋》二:“ 长江蕴藏着无限丰富的水能; 三峡 形成了天然的水利枢纽。这在我国的建设事业中,有可能变成一种巨大的能力。”


毛泽东在《纪念白求恩》中写道:“一个人能力有大小,但只要有这点精神,就是一个高尚的人。”

领导在平台开工会中提到:“一个平台能力有大有小,但只要架构优秀并持续改进,就是一个有希望的平台”


从上面的名家言论中可以看出,能力是对人、物等特定载体在某些场景下所表现出的一组行为的描述。



打个比方,我们在谈到“人”这个能力载体时,我们会说:

  • 人具备改变世界的能力

  • 人具备繁衍后代的能力

  • 人具备扯淡的能力

  • 相声演员(人的实例)具备说学逗唱的能力

  • 体育运动员(人的实例)具备跑跳的能力

  • .............

2、能力的特征

如果我们再进一步细分,人这个载体又是由头、躯干、四肢、经血、脉络以及各种内脏组成。这些不同的部件,也可以做为一个载体提供一些更加细分、具体的能力。 比如,手这个载体,虽然他不具备繁衍后代的能力。但是手的能力有:可以弯曲的能力、可以负重的能力。 手弯曲的行为有手腕弯曲、手指弯曲,手的负重行为可以有以手掌方式负重、手指方式负重。 手这个部件的能力以及其行为虽然很有限,但是配合起来可以完成俯卧撑,最终支撑并实现了人类繁衍更加重要能力的实现。


所以,能力是可聚合的


说到了能力的行为,行为应该可以扩展的,扩展后的行为可以做更多的之前做不到的事。比如挠痒这个行为。其实挺简单,基本的挠痒动作就是用手去抓嘛,能抓得到的地方就去抓好了。但对于抓不到的地方,那怎么办? 你至少有两种选择:

  1. 换个行为,改用“蹭”,找个地方对准痒处使劲蹭..

  2. 还是用“挠”这个行为,不过得扩展一下手,在配合使用“不求人”完成对痒处的“挠”


所以,能力的行为是可扩展的


刚刚提到的手的能力及其行为,都原生的,与生俱来的。但是,我们是可以通过给人增加外挂,增加一些原本不具备的能力。比如,给眼睛配上夜视眼镜,人就具备了如猫一样可以夜视行为。 夜视眼镜的载体是眼睛,对看这个行为进行了扩展,从而使人具备夜视的能力。


所以,某些能力不一定是原生的,是可以通过工具后可叠加的

有时,你在某个方面可能真的很牛逼。比如,你唱歌很好、舞跳得棒、乒乓球也是一把好手。 可是,在程序员的世界里,你说了,大家也不见得会在意和记住。 但你不说,你就很有可能失去一次和女神一起去嗨歌的好机会。


所以,能力是一定要可呈现的,至少是对特定的场景/视图

如果能理解上面的概念,那么在回过头来看 Lattice 中关于能力接口的定义。

在 Lattice 中,我们定义了能力接口 IAbility,其接口定义有两个泛型,第一个是能力载体(AbilityTarget),另一个是能力的行为(也叫可扩展点 IExtensionPoints)。

public interface IAbility<BusinessExt extends IBusinessExt> {
/** * @return current ability's unique code. */ String getCode();
/** * @return current domain ability's instance unique code. */ String getInstanceCode();

AbilityContext getContext();
/** * Whether current ability support current bizObject * * @return default return true. */ boolean supportChecking();

/** * Whether current ability support customization from plugin's extension realization. * * @return true or false. */ boolean supportCustomization();
/** * Whether current ability invoke getDefaultRealization() if the extension * realizaiton not found in the Plugin. * * @return true or false. */ boolean hasDefaultExtension();

/** * get the extension points' realization by business code. * * @return the ExtensionPoints realization. */ BusinessExt getDefaultRealization();

/** * @param callback callback of the function. * @param reducer The multi-result reduce policy. * @return the result of extension customization. */ <T, R> R reduceExecute(ExtensionCallback<BusinessExt, T> callback, @Nonnull Reducer<T, R> reducer);}
复制代码


IAbility 能力中有两个关键的方法,一个是 supportChecking。 是用来检查在特定的业务约束下(bizCode),对于特定的载体,本能力是否支持?简单的打比方:

  • 看”这个行为,去问“手”这个载体,应该得到 false 的结果

  • “看”这个行为去问“眼睛”,应该得到 true 的结果


另一个方法是 getDefaultRealization() 获取行为的实例。 比如:

  • 针对眼睛这个载体获取出 EmptyEyeExtension,那么就代表没有可用行为,比如盲人

  • 针对眼睛这个载体取出的是基本实现 NormalEyeExtension,那么就可以完成基本看的行为

  • 针对眼睛这个载体取出的是增强版 EnhancedEyeExtension,那么就可以完成夜视行为

关于如何具体定义一个能力的样例,可以参考 《Quick Start


3、能力实例(Ability Instance)


在前面,我们介绍了“能力”这个概念。可以看到,能力就是对一种特定“模式”的抽象。 而针对这些“模式”能力抽象的具体实现,就称之为能力实例。


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


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


  • 传统快递配送物流方式,这个不多介绍。(本例中,我们定义 NormalLogisticsAbility)

  • 基于线下门店自提方式: 这种方式,货品发到门店,但交易订单产生后不会有实际物流,用户需要人肉到线下门店去提货。比如,买轮胎,轮胎不是寄到家里,而是自己开车去 4S 店去安装已购买好的轮胎。 (本例中,我们定义 OfflineLogisticsAbility)

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


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


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


@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
复制代码


3.3 能力实例总结


本例中,我们是以物流能力抽象举例。发散一下,在优惠场景下,也是同样可以抽象 “基础营销工具能力”,并基于这个能力定义出各种实际的营销工具实例,进行模式级扩展。基于模式级扩展,可以有效的保障平台内核的稳定。



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


Lattice 是一个强大的、轻量级的,面向业务定制高可扩展的业务管理框架。通过使用 Lattice 框架,可以对复杂的业务定制进行高效的组织与管理。关于 Lattice 框架简介,可参考:https://xie.infoq.cn/article/85fe94515a1ce0a8315550d62




发布于: 刚刚阅读数: 2
用户头像

毗卢道场

关注

架构师 2022-11-25 加入

专注面向高可扩展的业务框架、业务快速开发框架研究

评论

发布
暂无评论
Lattice - 模式级复用的能力定义_架构_毗卢道场_InfoQ写作社区