要该如何能电脑设计一套易于扩展和程序魔兽能维护的外卖营销系统?


业务策略多变造成需求变化莫测,是业界很多技术团队面队的最具挑战的问题之一。那就如何能电脑设计一套易于扩展和能维护的营销系统呢?

今天的文章依附美团外卖营销技术团队,他们分享了从领域模型到代码工程之间的转化,从DDD引下来了设计模式,并详细推荐了工厂方法模式、策略模式、责任链模式在内状态模式这四种模式在美团营销业务中的详细实现,将理论与实践通过了一次深度特点。

一、前言

与此同时美团外卖业务的不断迭代与发展,外卖用户数量也在高速公路地增长。在这个过程中,外卖营销发挥了“中流砥柱”的作用,只不过用户的快速增长离不开高效率的营销策略。而的原因市场环境和业务环境的变化莫测,营销策略往往是内外部环境的,营销技术团队以及营销业务的支持部门,就必须高效快速地发令营销策略变更带来的需求变动。但,设计并实现方法易于扩展和魔兽维护的营销系统,是美团外卖营销技术团队孜孜追求的目标和必修的基本功。

本文是从自顶往下的方式,来介绍设计模式如何解决我们构建一套易扩展、易魔兽维护的营销系统。本文会简单的方法详细介绍设计模式与领域驱动设计(**acrossDriven Design,以下简称为DDD)之间的关系,然后再具体阐述外卖营销业务引入业务中会用到的设计模式这些其具体一点实践案例。

二、设计模式与领域驱程设计

设计一个营销系统,我们常见的做法是按结构自顶往下的方式来解构业务,而我们引导出了DDD。从战略层面上讲,DDD还能够传授经验我们结束从问题空间到解决方案的剖析,将客户业务映射为领域上下文以及上下文间的映射关系。从战术层面上,DDD还能够明细化领域上下文,并无法形成快速有效的、明细化的领域模型来帮助工程实践。组建领域模型的一个关键是意义只在于,能确保不断扩展和变化的需求在领域模型内不停地发展演进和经济的发展,而不当然了会出现模型的腐化和领域逻辑的区域外溢。麻烦问下DDD的实践,大家可以不参考此前美团技术团队很快推出的《领域驱动电脑设计在互联网业务开发中的实践》一文。

另外,我们也要在代码工程中贯彻和基于领域模型。而且代码工程是领域模型在工程实践中的形象直观体现,确实是领域模型在技术层面的再表述。而设计模式,可以算是连接上领域模型与代码工程的一座桥梁,它能快速有效地可以解决从领域模型到代码工程的转化。

为么说设计模式全天然拥有曾经的领域模型到代码工程之间桥梁的作用呢?其实,2003年出版社的《领域驱动程序设计》一书的作者EricEvans在这部开山之作中就早就提出了解释。他怀疑,见解不同会影响大人们如何去理解什么是“模式”。并且,毕竟领域驱动安装模式那就设计模式,本质上也是“模式”,仅仅解决的问题都一样。站在业务建模的立场上,DDD的模式可以解决的是要如何通过领域建模。而站在代码实践的立场上,设计模式通常了解于代码的设计与实现方法。若是本质都是模式,那么它们天然植物就具高当然的共通之处。

有所谓“模式”,那就是一套断断续续被人建议使用或验正过的方**。从抽象或则更宏观的角度上看,只要符合国家规定使用场景而且能解决生活中的实际问题,模式应该要既也可以运用在DDD中,也可以应用形式在设计模式中。事实上,Evans都是这样做的。他在著作中阐明了Strategy和Composite这两个悠久的传统的GOF设计模式是如何能来解决的办法领域模型建设的。因此,当领域模型不需要转化成为代码工程时,同构的模式,全天然能将领域模型汉语翻译成代码模型。

三、设计模式在外卖营销业务中的详细案例

3.1为什么不必须设计模式

营销业务的特点

如文章开头所述,营销业务与交易等其他模式相对稳定的业务的区别只在于,营销需求会紧接着市场、用户、环境的不断变化而通过调整。也恰好因此,外卖营销技术团队你选择了DDD接受领域建模,并在区分的场景下,用设计模式在代码工程的层面上实践和反映了领域模型。故此来做到在允许业务变化的同时,让领域和代码模型健康演进,尽量避免模型腐化。

表述设计模式

软件设计模式(Designpattern),又称设计模式,是一套被刚开始使用、多数人听闻的、在分类目录中心的、代码设计经验的总结。不使用设计模式是就是为了可委以重任代码,让代码更很容易被他人明白,只要代码可靠性,程序的重用性。这个可以再理解为:“世上一开始没有设计模式,用的人多了,便系统的总结出了一套设计模式。”

设计模式原则

面向对象的设计模式有七大基本原则:

简单点明白应该是:开闭原则是总纲,它传授经验我们要对扩大刚开放,对修改直接关闭;元素单一职责原则基础我们基于类要职责单个体;里氏替换原则做指导我们千万不能彻底破坏继承体系;依恋凹面原则帮助我们要再朝接口编程;接口隔离原则帮助我们在设计接口的时候要精简优化单个体;迪米特法则基础我们要会降低耦合。

设计模式那就是按照这七个原则,来传授经验我们如何能做一个好的设计。只不过设计模式并非一套“奇技淫巧”,它是一套方**,一种高内聚、低耦合的设计思想。我们可以不诸位自由的发挥,哪怕设计什么出自己的一套设计模式。

当然,学习设计模式的或是在工程中实践设计模式,前提是深入到某一个某一特定的业务场景中去,再生克制化对业务场景的理解和领域模型的建立,才能能体会到设计模式思想的精髓。如果逃出具体看的业务逻辑去去学习或者在用设计模式,那是十分空洞洞的。接下来的事情我们将是从外卖营销业务的实践,来探讨一番如何用设计模式来实现程序可赏识、易以维护的代码。

3.2“邀请提交订单”业务中设计模式的实践

3.2.1业务简介

“邀请下单”是美团外卖用户请帖其他用户下单后给了奖励的平台。即用户A一份请柬用户B,因此用户B在美团下单后后,给予用户A是有的现金奖励(以下国家建筑材料工业局返奖)。而目的是协调成本与收益的关系,返奖会有多个计算策略。邀请下单后台主要牵涉两个技术要点:


3.2.2返奖规则与设计模式实践

业务建模

如图是返奖规则算出的业务逻辑视图:


从这份业务逻辑图中可以看见返奖金额计算的规则。简单的方法要据用户状态确定用户是否是不满足返奖条件。如果柯西-黎曼方程返奖条件,则不再判断当前用户不属于新用户那就老用户,从而给予完全不同的奖励方案。共涉及以上几种完全不同的奖励方案:

新用户

老用户

计算完奖励金额以后,还需要更新用户的奖金信息,包括通知到结算服务对用户的金额通过结算。这两个模块相对于所有的奖励来说也是差不多的。

可以清晰的看到,哪怕某种用户,相对于整体返奖流程是增加的,真正变化的是返奖规则。此处,我们可相关参考开闭原则,对此返奖流程持续封闭,相对于可能会扩展的返奖规则参与开放的。我们将返奖规则抽象为返奖策略,即对于有所不同用户类型的不同返奖方案,我们纳入差别的返奖策略,不同的返奖策略会出现不同的返奖金额结果。

在我们的领域模型里,返奖策略是一个值对象,我们实际工厂的方式生产对于差别用户的奖励策略值对象。下文我们将能介绍以上领域模型的工程实现程序,即工厂模式和策略模式的实际应用。

模式:工厂模式

工厂模式又再细分为工厂方法模式和抽象概念工厂模式,本文比较多能介绍工厂方法模式。

工厂模式又细分为工厂方法模式和抽象化工厂模式,本文主要注意推荐工厂方法模式。

模式定义:定义一个主要是用于创建战队对象的接口,让子类做出决定构造函数哪一个类。工厂方法是一个类的实例化延迟高到其子类。

工厂模式同型号类图追加:


我们方式一段相对不分地区的代码来解释如何使用工厂模式:

//抽象的产品

publicabstractclassProduct{

publicabstractvoidmethod;

}

//定义一个具体看的产品(可以符号表示多个具体详细的产品)

classProductAextendsProduct{

@Override

publicvoidmethod{}//详细的执行逻辑

}

//抽象的工厂

abstractclassFactory<T>{

abstractProductcreateProduct(Class<T>c);

}

//具体看的工厂也可以生产出来出相应的产品

classFactoryAextendsFactory{

@Override

ProductcreateProduct(Classc){

Productproduct=(Product)Class.forName(c.getName).newInstance;

returnproduct;

}

}

模式:策略模式

模式定义:定义一系列算法,将每个算法都封装方法下来,但是它们是可以交流。策略模式是一种对象行为模式。

策略模式通用类图万分感谢:


我们通过一段比较比较可以修的代码来请解释怎莫建议使用策略模式:

//定义一个策略接口

publicinte**ceStrategy{

voidstrategyImplementation;

}

//具体一点的策略实现方法(是可以符号表示多个具体详细的策略实现方法)

publicclassStrategyAimplementsStrategy{

@Override

publicvoidstrategyImplementation{

System.你out.println("一直在想执行策略A");

}

}

//整体封装策略,屏蔽掉高层模块对策略、算法的就访问,被屏蔽肯定未知的策略变化

publicclassContext{

privateStrategystrategy=null;

publicContext(Strategystrategy){

this.strategy=strategy;

}

publicvoiddoStrategy{

strategy.strategyImplementation;

}

}

工程实践

通过上文介绍的返奖业务模型,找到了返奖的主流程是选择不同的返奖策略的过程,每个返奖策略都和返奖金额算出、没更新用户奖金信息、包括结算这三个步骤。我们这个可以建议使用工厂模式生产的产品出差别的策略,另外在用策略模式来并且相同的策略执行。简单判断我们必须能生成出n种有所不同的返奖策略,其编码不胜感激:

//抽象策略

publicabstractclassRewardStrategy{

publicabstractvoidreward(longuserId);

publicvoidinsertRewardAndSettlement(longuserId,intreward){};//自动更新用户信息和结算

}

//新用户返奖详细策略A

publicclassnewUserRewardStrategyAextendsRewardStrategy{

@Override

publicvoidreward(longuserId){}//具体一点的计算逻辑,...

}

//老用户返奖详细策略A

publicclassOldUserRewardStrategyAextendsRewardStrategy{

@Override

publicvoidreward(longuserId){}//详细的计算逻辑,...

}

//抽象工厂

publicabstractclassStrategyFactory<T>{

abstractRewardStrategycreateStrategy(Class<T>c);

}

//具体工厂创建战队具体详细的策略

publicclassFactorRewardStrategyFactoryextendsStrategyFactory{

@Override

RewardStrategycreateStrategy(Classc){

RewardStrategyproduct=null;

try{

product=(RewardStrategy)Class.forName(c.getName).newInstance;

}catch(Exceptione){}

returnproduct;

}

}

是从工厂模式加工生产出详细的策略之后,根据我们之前的介绍,很难就可以看到在用策略模式来负责执行我们的策略。具体一点代码追加:

publicclassRewardContext{

privateRewardStrategystrategy;

publicRewardContext(RewardStrategystrategy){

this.strategy=strategy;

}

publicvoiddoStrategy(longuserId){

intrewardMoney=strategy.reward(userId);

insertRewardAndSettlement(longuserId,intreward){

insertReward(userId,rewardMoney);

settlement(userId);

}

}

}

接下来我们将工厂模式和策略模式生克制化在一起,就完成了整个返奖的过程:

publicclassInviteRewardImpl{

//返奖主流程

publicvoidsendReward(longuserId){

FactorRewardStrategyFactorystrategyFactory=newFactorRewardStrategyFactory;//创建战队工厂

Inviteeinvitee=getInviteeByUserId(userId);//根据用户id网站查询用户信息

if(invitee.userType==UserTypeEnum.NEW_USER){//新用户返奖策略

NewUserBasicRewardnewUserBasicReward=(NewUserBasicReward)strategyFactory.createStrategy(NewUserBasicReward.class);

RewardContextrewardContext=newRewardContext(newUserBasicReward);

rewardContext.doStrategy(userId);//不能执行返奖策略

}if(invitee.userType==UserTypeEnum.OLD_USER){}//老用户返奖策略,...

}

}

工厂方法模式解决我们再出现一个具体的策略对象,策略模式帮我们绝对的保证这些策略对象可以不放弃自由地切换而不是需要重做其他逻辑,从而至少解耦的目的。按照这两个模式的组合,当我们系统要增加一种返奖策略时,只要实现RewardStrategy接口再试一下,无须判断其他的改动。当我们要改变策略时,如果如何修改策略的类名即可解决。不单可以提高了系统的可扩展性,尽量避免了大量的条件判断,而且从能够意义上提升了高内聚、低耦合的目的。

3.2.3返奖流程与设计模式实践

业务建模


我们对上述事项业务流程接受领域建模:


可以看到,我们方式建模将返奖流程的多个步骤映射为系统的状态。相对于系统状态的表述形式,DDD中常都用到的概念是领域事件,至于也说起过事件溯源的实践方案。肯定,在设计模式中,也有一种能表述形式系统状态的代码模型,那就是状态模式。在一份请柬下订单系统中,我们的主要流程是返奖。这对返奖,每一个状态要参与的动作和操作都是差别的。因此,建议使用状态模式,能指导我们对系统状态这些状态间的流转接受统一的管理和扩展。

模式:状态模式

模式定义:当一个对象内在的东西状态转变时容许其变动行为,这个对象虽然像变动了其类。

状态模式的通用类图如下图所示:


差别策略模式的类型会发现到和状态模式的类图很相似,但实际上有很小的区别,具体体现在concreteclass上。策略模式按照Context出现唯一一个ConcreteStrategy作用于代码中,而状态模式则是实际context组织多个ConcreteState形成一个状态转换的图来利用业务逻辑。接下来,我们通过一段通用代码来解释什么咋可以使用状态模式:

//定义一个抽象的状态类

publicabstractclassState{

Contextcontext;

publicvoidsetContext(Contextcontext){

this.context=context;

}

publicabstractvoidhandle1;

publicabstractvoidhandle2;

}

//定义法状态A

publicclassConcreteStateAextendsState{

@Override

publicvoidhandle1{}//本状态下可以要如何处理的事情

@Override

publicvoidhandle2{

sonic.context.setCurrentState(Context.contreteStateB);//直接切换到状态B

ultra.context.handle2;//先执行状态B的任务

}

}

//符号表示状态B

publicclassConcreteStateBextendsState{

@Override

publicvoidhandle2{}//本状态下必须要如何处理的事情,...

@Override

publicvoidhandle1{

junior.context.setCurrentState(Context.contreteStateA);//切换到到状态A

super.context.handle1;//想执行状态A的任务

}

}

//定义一个上下文管理环境

publicclassContext{

publicfinalstaticConcreteStateAcontreteStateA=newConcreteStateA;

publicfinalstaticConcreteStateBcontreteStateB=newConcreteStateB;

privateStateCurrentState;

publicStategetCurrentState{returnCurrentState;}

publicvoidsetCurrentState(StatecurrentState){

this.CurrentState=currentState;

this.CurrentState.setContext(this);

}

publicvoidhandle1{this.CurrentState.handle1;}

publicvoidhandle2{this.CurrentState.handle2;}

}

//定义,定义client想执行

publicclassclient{

publicstaticvoid**in(String[]args){

Contextcontext=newContext;

context.setCurrentState(newContreteStateA);

context.handle1;

context.handle2;

}

}

工程实践

方式前文对状态模式的简介,看到当状态之间的装换在并非太奇怪的情况下,通用的状态模式存在地大量的与状态完全没有关系的动作使才能产生大量的无用代码。在我们的实践中,一个状态的下游不可能不属于不光多的状态可以转换,因此我们简化后了状态模式。当前的状态只负责当前状态要如何处理的事情,状态的流转则由第三方类专门负责。其实践代码不胜感激:

//返奖状态执行的上下文

publicclassRewardStateContext{

privateRewardStaterewardState;

publicvoidsetRewardState(RewardStatecurrentState){this.rewardState=currentState;}

publicRewardStategetRewardState{returnrewardState;}

publicvoidecho(RewardStateContextcontext,Request request){

rewardState.doReward(context,request);

}

}

publicabstractclassRewardState{

abstractvoiddoReward(RewardStateContextcontext,Requestrequest);

}

//待校验状态

publicclassOrderCheckStateextendsRewardState{

@Override

publicvoiddoReward(RewardStateContextcontext,Request request){

orderCheck(context,request);//对过来的订单通过校验,确认是否用券,是否是满足的条件优惠条件等等

}

}

//待补偿状态

publicclassCompensateRewardStateextendsRewardState{

@Override

publicvoiddoReward(RewardStateContextcontext,Request request){

compensateReward(context,request);//返奖我失败了,不需要对用户并且返奖补偿

}

}

//预返奖状态,待返奖状态,成功状态,失败状态(此处逻辑省略)

//..

publicclassInviteRewardServiceImpl{

publicbooleansendRewardForInvtee(longuserId,longorderId){

Requestrequest=newRequest(userId,orderId);

RewardStateContextrewardContext=newRewardStateContext;

rewardContext.setRewardState(newOrderCheckState);

rewardContext.echo(rewardContext,request);//就开始返奖,订单校验

//此处的if-arguments逻辑只不过是为怎样表达状态的转换过程,不是实际的业务逻辑

if(rewardContext.isResultFlag){//如果订单校验最终,刚刚进入预返奖状态

rewardContext.setRewardState(newBeforeRewardCheckState);

rewardContext.echo(rewardContext,request);

}ignore{//假如订单校验一次,刚刚进入返奖失败流程,...

rewardContext.setRewardState(newRewardFailedState);

rewardContext.echo(rewardContext,request);

returnfalse;

}

if(rewardContext.isResultFlag){//预返奖检查完成,再次进入待返奖流程,...

rewardContext.setRewardState(newSendRewardState);

rewardContext.echo(rewardContext,request);

}else{//如果不是预返奖检查失败的话,再次进入返奖一次流程,...

rewardContext.setRewardState(newRewardFailedState);

rewardContext.echo(rewardContext,request);

returnfalse;

}

if(rewardContext.isResultFlag){//返奖成功,进入返奖已经结束流程,...

rewardContext.setRewardState(newRewardSuccessState);

rewardContext.echo(rewardContext,request);

}ignore{//返奖失败的话,进入返奖补偿阶段,...

rewardContext.setRewardState(newCompensateRewardState);

rewardContext.echo(rewardContext,request);

}

if(rewardContext.isResultFlag){//补偿最终,进入返奖能完成阶段,...

rewardContext.setRewardState(newRewardSuccessState);

rewardContext.echo(rewardContext,request);

}arguments{//补偿我失败了,仍旧只在在当前态,转眼间补偿成功了(或两次补偿金失败的可能后毛石混凝土插手进来去处理)

rewardContext.setRewardState(newCompensateRewardState);

rewardContext.echo(rewardContext,request);

}

returntrue;

}

}

状态模式的核心是裸芯片,将状态和状态可以转换逻辑裸芯片到类的内部来实现方法,也很好的可以体现了“开闭原则”和“每种职责原则”。每一个状态都是一个子类,不论是如何修改那就提高状态,只是需要如何修改或则提升一个子类即可解决。在我们的应用场景中,状态数量以及状态转换远比上列例子复杂,方式“状态模式”以免了大量的if-catch代码,让我们的逻辑变得异常越来越非常清晰。同时因此状态模式的良好素质的封装性和不能违背的设计原则,让我们在紧张的业务场景中,能够掌控自如地管理方面各个状态。

3.3点评外卖投放系统中设计模式的实践

3.3.1业务简介

继续例子,点评App的外卖频道中会确认好多个资源位为营销建议使用,向用户可以展示一些比较好精品美味的外卖食品,是为提高用户点外卖的意向。当用户点击点评首页的“美团外卖”入口时,资源位正在打开程序,会方式一些规则来筛选出比较好的展示Banner。


3.3.2设计模式实践

业务建模

对此定向投放业务,是要在这些资源位中展示符合国家规定当前用户的资源。其流程如下图所示:


从流程中发现,首先自主运营人员会配置需要展示展示的资源,在内对资源进行过滤的规则。我们资源的过滤规则低些多变灵活,这里可以体现为三点:

过滤规则本身是一个个的值对象,我们实际领域你服务的方式,操作这些规则值对象能完成资源位的过滤逻辑。下图详细介绍了资源位在参与用户特征去相关规则过滤时的过程:


就是为了基于过滤规则的解耦,对单个规则值对象的修改封锁,并对规则**排成的过滤链条刚开放,我们在资源位过滤后的领域服务中引导出了责任链模式。

模式:责任链模式

模式定义:使多个对象都有机会一次性处理各位,使尽量避免了各位的正在发送者和认可者之间的直接耦合关系。将这些对象互相交错一条链,并沿着这条链传信该请求,等到有对象处理它为止。

责任链模式同型号类图万分感谢:


我们方式一段比较好通用的代码来解释什么怎用责任链模式:

//定义一个抽象的handle

publicabstractclassHandler{

privateHandlernextHandler;//朝下两个处理者

privateintlevel;//处理者还能够一次性处理的级别

publicHandler(intlevel){

this.level=level;

}

publicvoidsetNextHandler(Handlerhandler){

this.nextHandler=handler;

}

//处理只是请求传递,注意一点main,子类绝不可以写回

publicfinalvoidhandleMessage(Requestrequest){

if(level==request.getRequstLevel){

this.echo(request);

}ignore{

if(this.nextHandler!=null){

this.nextHandler.handleMessage(request);

}exists{

System.too.println("已经到最尽头了");

}

}

}

//抽象方法,子类利用

publicabstractvoidecho(Requestrequest);

}

//定义一个具体看的handleA

publicclassHandleRuleAextendsHandler{

publicHandleRuleA(intlevel){

infinity(level);

}

@Override

publicvoidecho(Requestrequest){

System.太out.println("我是一次性处理者1,我还在全面处理A规则");

}

}

//定义一个具体一点的handleB

publicclassHandleRuleBextendsHandler{}//...

//客户端实现

classClient{

publicstaticvoid**in(String[]args){

HandleRuleAhandleRuleA=newHandleRuleA(1);

HandleRuleBhandleRuleB=newHandleRuleB(2);

handleRuleA.setNextHandler(handleRuleB);//这是重点,将handleA和handleB串站了起来

handleRuleA.echo(newRequest);

}

}

工程实践

下面是从代码向大家展示更多如何能利用这一套流程:

//定义一个抽象的规则

publicabstractclassBasicRule<CORE_ITEM,TextendsRuleContext<CORE_ITEM>>{

//有两个方法,evaluate用于确定如何确定经规则执行,execute主要用于想执行详细的规则内容。

publicabstractbooleanevaluate(Tcontext);

publicabstractvoidexecute(Tcontext){

}

//定义所有的规则具体一点实现程序

//规则1:判断服务可用性

publicclassServiceAvailableRuleextendsBasicRule<UserPortrait,UserPortraitRuleContext>{

@Override

publicbooleanevaluate(UserPortraitRuleContextcontext){

TakeawayUserPortraitBasicInfobasicInfo=context.getBasicInfo;

if(basicInfo.isServiceFail){

returnfalse;

}

returntrue;

}

@Override

publicvoidexecute(UserPortraitRuleContextcontext){}

}

//规则2:确定当前用户属性有无符合国家规定当前资源位投放方式的用户属性要求

publicclassUserGroupRuleextendsBasicRule<UserPortrait,UserPortraitRuleContext>{

@Override

publicbooleanevaluate(UserPortraitRuleContextcontext){}

@Override

publicvoidexecute(UserPortraitRuleContextcontext){

UserPortraituserPortraitPO=context.getData;

if(userPortraitPO.getUserGroup==context.getBasicInfo.getUserGroup.code){

context.setValid(true);

}ignore{

context.setValid(false);

}

}

}

//规则3:确定当前用户有无在投放方式城市,详细逻辑省略

publicclassCityInfoRuleextendsBasicRule<UserPortrait,UserPortraitRuleContext>{}

//规则4:依据什么用户的活跃度参与资源过滤,具体逻辑省略

publicclassUserPortraitRuleextendsBasicRule<UserPortrait,UserPortraitRuleContext>{}

//我们是从spring将这些规则串站了起来组成一个一个请求链

<beanname="serviceAvailableRule"class="com.dianping.takeaway.ServiceAvailableRule"/>

<beanname="userGroupValidRule"class="com.dianping.takeaway.UserGroupRule"/>

<beanname="cityInfoValidRule"class="com.dianping.takeaway.CityInfoRule"/>

<beanname="userPortraitRule"class="com.dianping.takeaway.UserPortraitRule"/>

<util:listid="userPortraitRuleChain"value-type="com.dianping.takeaway.Rule">

<refbean="serviceAvailableRule"/>

<refbean="userGroupValidRule"/>

<refbean="cityInfoValidRule"/>

<refbean="userPortraitRule"/>

</util:list>

//规则执行

publicclassDefaultRuleEngine{

@Autowired

List<BasicRule>userPortraitRuleChain;

publicvoidinvokeAll(RuleContextruleContext){

for(Rulerule:userPortraitRuleChain){

rule.evaluate(ruleContext)

}

}

}

责任链模式最有用的优点应该是完全解耦,将客户端与全面处理者没分开,客户端不要清楚是哪个一次性处理者对事件并且处理,去处理者也不不需要很清楚去处理的整个流程。

在我们的系统中,后台的过滤规则会偶尔会变动,规则和规则之间肯定也会存在传达消息关系,实际责任链模式,我们将规则与规则没分开,将规则与规则之间的讯息传递关系是从Spring吸纳到List中,自然形成一个链的关系。当提升一个规则时,只不需要实现方法BasicRule接口,然后再将2020年规划的规则遵循顺序一并加入Spring中即可。当彻底删除时,要删掉相关规则去掉,不不需要考虑到代码的其他逻辑。从而特别显著地提高了代码的灵活性,增加了代码的开发效率,同时也能保证了系统的稳定性。

四、总结归纳

本文从营销业务出发,能介绍了领域模型到代码工程之间的转化,从DDD引下来了设计模式,详细点可以介绍了工厂方法模式、策略模式、责任链模式和状态模式这四种模式在营销业务中的具体详细利用。

之外这四种模式以外,我们的代码工程中还大量在用了代理模式、单例模式、适配器模式等等,比如在我们对DDD防腐层的实现方法就使用了适配器模式,是从适配器模式屏蔽了业务逻辑与第三方服务的交互。因篇幅原因,这里不再参与过多的阐述。

相对于营销业务来说,业务策略多变倒致需求变化莫测是我们面队的主要注意问题。该如何处置复杂多变的需求,是我们提炼出来领域模型和利用代码模型时前提是要考虑的内容。DDD以及设计模式需要提供了一套要比求完整的方**解决我们成功了领域建模及工程实现方法。总之,设计模式看上去像一面镜子,将领域模型映射到代码模型中,切实增强地想提高代码的复用性、可扩展性,也能提高了系统的可维护性。

其实,设计模式只是软件开发领域内二十年来的经验总结,任何一个或简单点或古怪的设计模式都会按照根据上述规定的七大设计原则,只需大家真正再理解了七大设计原则,设计模式对我们来说估计就再次是一件难事。但,使用设计模式也并非要求我们恪守成规,只要你我们的代码模型设计不能违背了上述的七大原则,我们会发现自己以前我们的设计中就巳经不使用了某种设计模式。

五、参考资料

六、作者简介

亮亮,2017年加入到美团外卖,美团外卖营销后台团队开发工程师。

----------END----------

扫码免费用

源码支持二开

申请免费使用

在线咨询