美文网首页
2020-03-23

2020-03-23

作者: Coisini_42e7 | 来源:发表于2020-03-23 17:38 被阅读0次

    美团设计模式在外卖营销业务中的实践-学习笔记(一)

    美团设计模式在外卖营销业务中的实践-学习笔记(一)一、设计模式原则二、设计模式在美团外卖营销业务中的具体案例2.1、工厂模式和策略模式2.1.1 业务简介2.1.2 返奖规则与设计模式业务建模模式:工厂模式模式:策略模式工程实践:2.1.3 返奖流程与设计模式实践业务建模工程实践

    看了美团技术团队的 设计模式在外卖营销业务中的实践 一文后的一些记录,emmm为了证明我看过,哈哈,还有最后一个责任链模式暂时还不知道怎么弄。。。 感兴趣的可以点这里去看看原文,干货满满。第一次写学习笔记,不知道写的好不好,欢迎各位大佬评论交流,大家一起学习啊。

    一、设计模式原则

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

    开闭原则 (Open Closed Principle, OCP)

    单一职责原则(Single Responseibility Principle, SRP)

    里氏代换原则(Liskov Substitution Principle, LSP)

    依赖倒转原则(Dependency Inversion Principle, DIP)

    接口隔离原则(Interface Segregation Principle, ISP)

    合成/聚合复用原则(Composite/Aggregate Reuse Principle, CARP)

    最少知识原则(Least Knowledge Principle, LKP)或者迪米特法则(Law of Demeter, LOD)

    简单理解就是:开闭原则是总纲,它指导我们要对扩展开放,对修改关闭;单一职责原则则指导我们实现类要职责单一;里氏替换原则知道我们不要破坏继承体系;依赖倒置原则指导我们要面向接口编程;接口隔离原则指导我们在设计接口的时候要精简单一;迪米特法则则指导我们要降低耦合。

    二、设计模式在美团外卖营销业务中的具体案例

    2.1、工厂模式和策略模式

    学习设计模式或者是在工程中实践设计模式,必须深入到某一个特定的业务场景中去,再结合对业务场景的理解和领域模型的建立,才能体会到设计模式思想的精髓。在这里美团结合了其“邀请下单”业务来进行设计模式实践与分享。

    2.1.1 业务简介

    “邀请下单”是美团外面用户邀请其他用户下单后给予奖励的平台。即用户A邀请用户B,并且用户B在美团下单后给予用户A一定的现金奖励。同时为了协调成本与收益的关系,返奖会有多个计算策略。邀请下单后台主要涉及两个技术要点:

    返奖金额计算,涉及到不同的计算原则。

    从邀请开始到返奖结束的整个流程。

    2.1.2 返奖规则与设计模式

    业务建模

    模式:工厂模式

    // 抽象的产品

    publicabstractclassProduct{

    publicabstractvoidmethod();

    }

    // 产品A

    publicclassProductAextendsProduct{

    @Override

    publicvoidmethod() {

    System.out.println("This is ProductA");

       }

    }

    // 产品B

    publicclassProductBextendsProduct{

    @Override

    publicvoidmethod() {

    System.out.println("This is Product B");

       }

    }

    // 创建一个抽象的工厂

    publicabstractclassFactory<T>{

    publicabstractProductcreateProduct(Class<T>c)throwsException;

    }

    // 具体分工厂实现 (注意 这里知识命名为FactoryA,不是ProductA的专属工厂)

    publicclassFactoryAextendsFactory{

    @Override

    publicProductcreateProduct(Classc)throwsException{

    // 利用反射动态创建实例

    return(Product)Class.forName(c.getName()).newInstance();

       }

    }

    // 具体使用

    publicstaticvoidmain(String[]args)throwsException{

          //创建工厂

    FactoryAfactoryA=newFactoryA();

          // 使用工厂创建具体的产品

    Productproduct=factoryA.createProduct(ProductA.class);

    product.method();

    Productproduct1=factoryA.createProduct(ProductB.class);

    product1.method();

    }

    // 输出结果

    ConnectedtothetargetVM,address:'127.0.0.1:65319',transport:'socket'

    ThisisProductA

    ThisisProductB

    DisconnectedfromthetargetVM,address:'127.0.0.1:65319',transport:'socket'

    Processfinishedwithexitcode0

    模式:策略模式

    // 定义一个策略接口

    publicinterfaceStrategy{

    voidstrategyImplementation();

    }

    // 具体的策略实现

    publicclassStrategyAimplementsStrategy{

    @Override

    publicvoidstrategyImplementation() {

    System.out.println("正在执行策略A");

       }

    }

    publicclassStrategyBimplementsStrategy{

    @Override

    publicvoidstrategyImplementation() {

    System.out.println("正在执行策略B");

       }

    }

    // 策略封装 屏蔽高层模块对策略、算法的直接访问 使用context同一操作

    publicclassContext{

    privateStrategystrategy=null;

    publicContext(Strategystrategy){

    this.strategy=strategy;

       }

    publicvoiddoStrategy(){

    strategy.strategyImplementation();

       }

    }

    // 具体使用

    publicstaticvoidmain(String[]args)throwsException{

    StrategyAstrategy=newStrategyA();

    ContextcontextA=newContext(strategy);

    contextA.doStrategy();

    StrategyBstrategyB=newStrategyB();

    ContextcontextB=newContext(strategyB);

    contextB.doStrategy();

       }

    // 输出结果

    ConnectedtothetargetVM,address:'127.0.0.1:65488',transport:'socket'

    正在执行策略A

    正在执行策略B

    DisconnectedfromthetargetVM,address:'127.0.0.1:65488',transport:'socket'

    Processfinishedwithexitcode0

    工程实践:

    // 抽象策略

    publicabstractclassRewardStrategy{

    // 生成的返奖金额 不同策略实现不同 定义成抽象的 由子类自己实现

    publicabstractintreward(longuserId);

      // 更新账户及结算信息 每个用户和返奖规则最后都要执行 统一实现

    publicvoidinsertRewardAndSettlement(longuserId,intreward){

    System.out.println("更新用户信息以及结算成功:userId => "+userId+",reward => "+reward);

       }

    }

    // 新用户返奖策略 (这里使用随机数模拟返奖金额 😁)

    publicclassNewUserRewardStrategyextendsRewardStrategy{

    @Override

    publicintreward(longuserId) {

    System.out.println("新用户反奖策略,用户 => "+userId);

    return(int)(Math.random()*10);

       }

    }

    // 老用户返奖策略 (这里也使用随机数模拟返奖金额 😁)

    publicclassOldUserRewardStrategyextendsRewardStrategy{

    @Override

    publicintreward(longuserId) {

    System.out.println("老用户反奖策略,用户 => "+userId);

    return(int)(Math.random()*10);

       }

    }

    // 抽象工厂

    publicabstractclassStrategyFactory<T>{

    abstractRewardStrategycreateStrategy(Class<T>c);

    }

    // 具体的工厂 (根据具体的类生成不同的策略)

    publicclassFactorStrategyFactoryextendsStrategyFactory{

    @Override

    publicRewardStrategycreateStrategy(Classc) {

    RewardStrategystrategy=null;

    try{

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

    }catch(Exceptione){

    e.printStackTrace();

           }

    returnstrategy;

       }

    }

    // 使用策略模式来执行具体的策略

    publicclassRewardContext{

    privateRewardStrategystrategy;

      // 构造方法 传入具体到的策略

    publicRewardContext(RewardStrategystrategy){

    this.strategy=strategy;

       }

    publicvoiddoStrategy(longuserId){

    intreward=strategy.reward(userId);

    strategy.insertRewardAndSettlement(userId,reward);

       }

    }

    // 具体使用 使用时没有直接对策略、算法的直接访问 而是通过context进行操作

    // 这里使用随机数的大小来判断 使用 老用户策略还是新用户策略 😄

    publicstaticvoidmain(String[]args) {

    FactorStrategyFactoryfactory=newFactorStrategyFactory();

    RewardContextcontext;

    RewardStrategystrategy;

    doublei=Math.random();

    System.out.println(i);

    if(i>0.4){

    strategy=factory.createStrategy(OldUserRewardStrategy.class);

    context=newRewardContext(strategy);

    context.doStrategy(123456);

    }else{

    strategy=factory.createStrategy(NewUserRewardStrategy.class);

    context=newRewardContext(strategy);

    context.doStrategy(456789);

           }

    }

    // 执行结果

    ConnectedtothetargetVM,address:'127.0.0.1:49241',transport:'socket'

    0.4496623743530703// 这个是生成的随机数

    老用户反奖策略,用户=>123456

    更新用户信息以及结算成功:userId=>123456,reward=>3

    DisconnectedfromthetargetVM,address:'127.0.0.1:49241',transport:'socket'

    Processfinishedwithexitcode0

    业务建模

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

    publicabstractclassState{

    protectedStateContextcontext;

    publicvoidsetContext(StateContextcontext){

    this.context=context;

       }

    publicabstractvoidhandle1();

    publicabstractvoidhandle2();

    }

    // 定义A状态

    publicclassConcreteStateAextendsState{

    @Override

    publicvoidhandle1() {

    System.out.println("执行状态1。。。");

       }

    @Override

    publicvoidhandle2() {

    //切换为状态B

    super.context.setCurrentState(StateContext.concreteStateB);

    //执行状态B的任务

    super.context.handle2();

       }

    }

    // 定义B状态

    publicclassConcreteStateBextendsState{

    @Override

    publicvoidhandle1() {

    //切换回状态A

    super.context.setCurrentState(StateContext.cincreteStateA);

    //执行状态A的任务

    super.context.handle1();

       }

    @Override

    publicvoidhandle2() {

    System.out.println("正在执行状态B");

       }

    }

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

    publicclassStateContext{

    publicfinalstaticConcreteStateBconcreteStateB=newConcreteStateB();

    publicfinalstaticConcreteStateAconcreteStateA=newConcreteStateA();

    privateStatecurrentState;

    publicStategetCurrentState(){

    returncurrentState;

       }

    publicvoidsetCurrentState(StatecurrentState){

    this.currentState=currentState;

    this.currentState.setContext(this);

       }

    publicvoidhandle1() {this.currentState.handle1();}

    publicvoidhandle2() {this.currentState.handle2();}

    }

    // 使用示例

    publicstaticvoidmain(String[]args) {

    StateContextcontext=newStateContext();

    context.setCurrentState(newCincreteStateA());

    context.handle1();

    context.handle2();

    }

    // 运行结果 (在A状态中转换成状态B并执行状态B的方法)

    ConnectedtothetargetVM,address:'127.0.0.1:49837',transport:'socket'

    执行状态1。。。

    正在执行状态B

    DisconnectedfromthetargetVM,address:'127.0.0.1:49837',transport:'socket'

    Processfinishedwithexitcode0

    工程实践

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

    publicclassStateContext{

    privateStatestate;

    publicvoidsetState(Statestate){

    this.state=state;

       }

    publicStategetState(){returnstate;}

    publicvoidecho(StateContextcontext){

    state.doReward(context);

       }

    publicbooleanisResultFlag(){

    returnstate.isResultFlag();

       }

    }

    // 返奖状态抽象类

    publicabstractclassState{

    // 具体执行

    publicabstractvoiddoReward(StateContextcontext);

      // 判断是否通过改判断

    publicabstractbooleanisResultFlag();

    }

    // 各状态下的处理逻辑 根据上面的业务建模来实现的 这里还是用随机数来模拟流程是否执行成功

    // 订单状态检查

    publicclassCheckOrderStateextendsState{

    privatebooleanflag=false;

    @Override

    publicvoiddoReward(StateContextcontext) {

    System.out.println(context.getClass().getName());

    System.out.println("CheckOrderState 订单状态检查...");

    doublei=Math.random();

    if(i>0.4){

    flag=true;

           }

       }

    @Override

    publicbooleanisResultFlag() {

    returnflag;

       }

    }

    // 预返奖检查

    publicclassBeforeRewardCheckStateextendsState{

    privatebooleanflag=false;

    @Override

    publicvoiddoReward(StateContextcontext) {

    System.out.println(context.getClass().getName());

    System.out.println("BeforeRewardCheckState 预反奖状态检查...");

    doublei=Math.random();

    if(i>0.4){

    flag=true;

           }

       }

    @Override

    publicbooleanisResultFlag() {

    returnflag;

       }

    }

    // 返奖流程

    publicclassSendRewardCheckStateextendsState{

    privatebooleanflag=false;

    @Override

    publicvoiddoReward(StateContextcontext) {

    System.out.println(context.getClass().getName());

    System.out.println("SendRewardCheckState 待反奖状态检查...");

    doublei=Math.random();

    if(i>0.4){

    flag=true;

           }

       }

    @Override

    publicbooleanisResultFlag() {

    returnflag;

       }

    }

    // 补偿放奖流程

    publicclassCompentstateRewardStateextendsState{

    privatebooleanflag=false;

    @Override

    publicvoiddoReward(StateContextcontext) {

    System.out.println(context.getClass().getName());

    System.out.println("CompentstateRewardState 补偿反奖状态...");

    doublei=Math.random();

    if(i>0.4){

    flag=true;

           }

       }

    @Override

    publicbooleanisResultFlag() {

    returntrue;

       }

    }

    // 返奖失败状态

    publicclassRewardFailStateextendsState{

    @Override

    publicvoiddoReward(StateContextcontext) {

    System.out.println(context.getClass().getName());

    System.out.println("RewardFailState 反奖失败状态...");

       }

    @Override

    publicbooleanisResultFlag() {

    returnfalse;

       }

    }

    // 返奖成功状态

    publicclassRewardSuccessStateextendsState{

    @Override

    publicvoiddoReward(StateContextcontext) {

    System.out.println(context.getClass().getName());

    System.out.println("RewardSuccessState 反奖成功状态...");

       }

    @Override

    publicbooleanisResultFlag() {

    returnfalse;

       }

    }

    // 全部流程整合

    publicstaticvoidmain(String[]args) {

    dosomething();

       }

    publicstaticbooleandosomething(){

    StateContextcontext=newStateContext();

    context.setState(newCheckOrderState());

    context.echo(context);//订单流程校验

    //此处的if-else逻辑只是为了表达状态的转换过程,并非实际的业务逻辑

    if(context.isResultFlag()){// 订单校验成功 进入预返奖状态

    context.setState(newBeforeRewardCheckState());

    context.echo(context);

    }else{// 订单校验失败 进入返奖失败状态

    context.setState(newRewardFailState());

    context.echo(context);

    returnfalse;

           }

    if(context.isResultFlag()){// 预返奖检查成功 进入返奖状态

    context.setState(newSendRewardCheckState());

    context.echo(context);

    }else{// 预返奖检查失败 进入返奖失败状态

    context.setState(newRewardFailState());

    context.echo(context);

    returnfalse;

           }

    if(context.isResultFlag()){// 返奖成功 进入返奖成功状态

    context.setState(newRewardSuccessState());

    context.echo(context);

    }else{// 返奖失败。进入补偿放奖状态

    context.setState(newCompentstateRewardState());

    context.echo(context);

           }

    if(context.isResultFlag()){// 补偿返奖成功 进入成功状态

    context.setState(newRewardSuccessState());

    context.echo(context);

    }else{// 补偿返奖失败 这里可以继续补偿返奖 可以认为控制补偿返奖次数。这里直接退出了

    System.out.println("补偿反奖失败");

           }

    returntrue;

       }

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

    相关文章

      网友评论

          本文标题:2020-03-23

          本文链接:https://www.haomeiwen.com/subject/lbawyhtx.html