前言

最近做的一个项目是实现一个灰度发布的逻辑,具体来说就是当某个产品更新的时候,根据不同的用户决定是否对新版本可见。该功能本身是很容易实现的,但是考虑到可扩展性的问题,引入了Drools规则引擎,并且通过一些设计模式来进一步提高它的可扩展性,以应对之后可能不断发生变化的规则。

原始代码

由于规则并不十分复杂,所以项目中将许多的校验与判断逻辑统一封装到了Fact对象中,而在.drl文件中仅仅是做一些初始化工作,例如这里的场景是给每个用户设置一个新版本可见的延迟天数,达到了这个天数才能获取新版本,那么在.drl中就是将用户与延迟天数的映射关系做初始化。因此,最开始只需要一个Fact就行了:

在.drl文件中,初始化完成之后,仅仅需要调用这个Fact对象的releaseCheck(),然后就可以通过isRelease()方法决定是否发布新版本了。

可扩展性

由上面的简单分析可以看到,判断是否发布新版本的逻辑都封装在了releaseCheck()方法中,但这个方法中的许多步骤其实是冗余的,比如说参数校验、安全校验等等,如果每次增加新的Fact时都去写一模一样的重复代码,就显得十分不简洁且不利于维护了,因此,我们将该方法抽象出来,并且将其中最关键的判断逻辑doReleaseCheck()交由子类去实现,这样不同的Fact子类只需要实现各自的核心判断逻辑即可。此时的UML如下:

除此之外,对于调用方来说,是不需要关心Fact对象的创建过程的,尤其是当参数比较复杂的情况下。这时候就可以通过工厂方法模式,将创建对象的具体过程交给工厂类来完成:

这样,对于调用方来说,只需要传入一个UserInfo对象即可,具体需要用到它的哪些属性以及属性的一些校验工作则交由工厂类来实现,调用方可以直接拿到想要的Fact对象。

总结

通过模板方法,可以在抽象父类中先定义好整个方法的框架,并且让不同的子类去实现其中的某些核心步骤,这些核心步骤在父类中是抽象的;而通过工厂方法,使得调用者不再需要关心创建对象的具体过程,将许多繁琐的工作解耦了出去,由工厂类来负责实现。