关于营销系统的一些实战心得

简介: 关于营销系统的一些实战心得

营销系统是一个动态的、有机地结合的系统,经常会随着业务的不断变化发生调整,因此从事这一业务的开发可让我头疼了。


之前在工作中就不乏一次遇到过随意调整营销策略的情况,在部分场景下由于使用了硬编码的方式来实现,因此在调整策略的时候显得特别不灵活。


下边我列举一个曾经遇到过的应用场景:


业务部门需要上线一款新型的产品,用户在线上购买了对应的产品,然后下单支付之后需要享受不同的服务内容,这些服务包含了赠送优惠券,发送红包补贴,加积分,升级等服务项。并且上线之后,可能会随着市场的因素的调整,部分服务内容也会有所下架,后期调整因素极高。


下边是一张用户建模的图:


网络异常,图片无法展示
|


线上买单,到选择购买的产品类型,再到后续下单之后执行不同的营销规则,每个产品对应不同的服务项目并且服务项目的内容还可能会随时调整。


举个实际案例来说,线上有这么几款服务产品供消费者选购:


1.999元会员套餐

正常会员服务期1个月

发放5张优惠券


2.1999元会员套餐

正常会员服务期2个月

发放6张优惠券

邀请新人加入app,新人在n天内购买套餐有优惠


3.2999元会员套餐

正常会员服务期3个月

发放7张优惠券

满2500元消费,返现50元红包

大致看看,不同的产品对应不同的促销规则,似乎毫无规律可言。


但是如果通过抽象的逻辑将其中的共同部分抽取出来,就会发现其实是有规则可循了。

下边我给出来一段 “不那么完整的代码案例” (关于这种营销手段的设计核心在于思路,没有完美的代码,只有不断精进的设计)


这段代码主要采用来策略模式的设计思路,不同的产品对应不同的策略,产品和策略之间的关联可以通过使用数据库的方式来做绑定。


首先可以将每个服务项目看作是一条营销的规则手段,因此我定义来一个marketing对象:


/**
 * 营销对象实体类
 *
 * @Author idea
 * @Date created in 9:39 上午 2020/5/4
 */
@NoArgsConstructor
@Data
@Builder
@AllArgsConstructor
public class MarketingPO {
    /**
     * 主键id
     */
    private Integer id;
    /**
     * 营销手段名称 存储class的名称
     */
    private String marketingName;
    /**
     * 入参 多个可以逗号分割
     */
    private String inputVal;
    /**
     * 描述
     */
    private String des;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 更新时间
     */
    private Date updateTime;
}
复制代码


接着便是产品和不同营销手段之间做关联


/**
 * 通过产品id和营销手段做关联
 *
 * @Author idea
 * @Date created in 3:37 下午 2020/5/4
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MarketingProductPO {
    /**
     * 主键id
     */
    private Integer id;
    /**
     * 营销工具id
     */
    private Integer marketingId;
    /**
     * 产品编号
     */
    private String productNo;
    /**
     * 描述
     */
    private String des;
    /**
     * 是否有效
     */
    private Integer validStatus;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 更新时间
     */
    private Date updateTime;
}
复制代码


接着是dao层的部分,不过这里我简单化地将持久层逻辑写在来代码里面,只做参考:


/**
 * 模拟dao层操作
 *
 * @Author idea
 * @Date created in 10:20 上午 2020/5/4
 */
@Repository
public class MarketingDao implements IMarketingDao {
    private static List<MarketingPO> MARKETING_LIST = new ArrayList();
    static {
        MarketingPO disCountMarket = MarketingPO.builder()
                .id(1).marketingName("com.sise.idea.present.impl.DiscountStrategy").des("折扣优惠").inputVal("7").build();
        MarketingPO redPacketMarket = MarketingPO.builder()
                .id(2).marketingName("com.sise.idea.present.impl.RedPacketStrategy").des("红包优惠").inputVal("8").build();
        MarketingPO newMemberCouponMarket = MarketingPO.builder()
                .id(3).marketingName("com.sise.idea.present.impl.NewMemberCouponStrategy").des("新人优惠券发送").inputVal("10").build();
        MARKETING_LIST.add(newMemberCouponMarket);
        MARKETING_LIST.add(disCountMarket);
        MARKETING_LIST.add(redPacketMarket);
    }
    @Override
    public List<MarketingPO> selectMarketingByIds(List<Integer> idList) {
        List<MarketingPO> marketingPOS = new ArrayList<>(idList.size());
        for (MarketingPO marketingPO : MARKETING_LIST) {
            if (idList.contains(marketingPO.getId())) {
                marketingPOS.add(marketingPO);
            }
        }
        return marketingPOS;
    }
}
/**
 * @Author idea
 * @Date created in 3:45 下午 2020/5/4
 */
@Repository
public class MarketingProductDao implements IMarketingProductDao {
    private static List<MarketingProductPO> MARKET_PRODUCT_LIST = new ArrayList<>();
    static {
        MarketingProductPO marketingProductPO = MarketingProductPO.builder()
                .productNo("p111")
                .marketingId(2)
                .validStatus(1)
                .des("2999套餐-发放优惠券")
                .build();
        MarketingProductPO marketingProductPO2 = MarketingProductPO.builder()
                .productNo("p111")
                .marketingId(3)
                .validStatus(1)
                .des("2999套餐-满额红包返现")
                .build();
        MARKET_PRODUCT_LIST.add(marketingProductPO);
        MARKET_PRODUCT_LIST.add(marketingProductPO2);
    }
    @Override
    public List<MarketingProductPO> selectByProductNo(String productNo) {
        List<MarketingProductPO> marketingProductPOS = new ArrayList<>();
        for (MarketingProductPO marketingProductPO : MARKET_PRODUCT_LIST) {
            //产品编码一致 而且规则有效
            if(marketingProductPO.getProductNo().equals(productNo) && marketingProductPO.getValidStatus()==1){
                marketingProductPOS.add(marketingProductPO);
            }
        }
        return marketingProductPOS;
    }
}
复制代码


接着便是对所有的营销手段都做了一层统一的封装和抽象:


package com.sise.策略模式.present;
/**
 * 关于营销手段的策略
 *
 * @Author idea
 * @Date created in 9:20 上午 2020/5/4
 */
public interface IMarketingStrategy {
    /**
     * 服务赠送的策略执行
     *
     * @param param 参数
     * @return
     */
    boolean doMarketing(Object ...param);
}
复制代码


接下来便是不同的营销手段对应不同的实现,这里面我简单做了一些实现:


@Service
public class RedPacketStrategy implements IMarketingStrategy {
    @Override
    public boolean doMarketing(Object... param) {
        System.out.println("红包赠送策略");
        return false;
    }
}
@Service
public class DiscountStrategy implements IMarketingStrategy {
    @Override
    public boolean doMarketing(Object... param) {
        System.out.println("打折优惠");
        return false;
    }
}
@Service
public class NewMemberCouponStrategy implements IMarketingStrategy {
    @Override
    public boolean doMarketing(Object... param) {
        System.out.println("新人赠送策略");
        return false;
    }
}
@Service
public class UpgradeStrategy implements IMarketingStrategy {
    @Override
    public boolean doMarketing(Object... param) {
        System.out.println("升级策略");
        return false;
    }
}
复制代码


既然有了不同营销手段的具体实现方式,那么对于购买不同的产品也需要查询到不同的营销手段,这个时候就需要有一个转换中间者的角色出现了:


/**
 * 营销工具核心执行器
 *
 * @Author idea
 * @Date created in 9:34 上午 2020/5/4
 */
public interface IMarketingCoreService {
    /**
     * 执行不同的营销工具
     *
     * @param productNo 产品编码
     * @return
     */
    boolean doMarketingJob(String productNo) throws Exception;
}
/**
 * 营销工具核心执行器
 *
 * @Author idea
 * @Date created in 9:34 上午 2020/5/4
 */
@Service
public class MarketingCoreService implements IMarketingCoreService {
    @Resource
    private IMarketingDao iMarketingDao;
    @Resource
    private IMarketingProductDao iMarketingProductDao;
    @Resource
    private ApplicationContext applicationContext;
    @Override
    public boolean doMarketingJob(String productNo) throws ClassNotFoundException {
        System.out.println("doMarketingJob begin =============");
        System.out.println(productNo);
        List<MarketingProductPO> marketingProductPOS = iMarketingProductDao.selectByProductNo(productNo);
        if (marketingProductPOS != null) {
            List<Integer> marketingIdList = marketingProductPOS.stream().map(MarketingProductPO::getMarketingId).collect(Collectors.toList());
            List<MarketingPO> marketingPOS = iMarketingDao.selectMarketingByIds(marketingIdList);
            for (MarketingPO marketingPO : marketingPOS) {
                String marketingName = marketingPO.getMarketingName();
                Class<?> clazz = Class.forName(marketingName);
                IMarketingStrategy marketingStrategy = (IMarketingStrategy) applicationContext.getBean(clazz);
                marketingStrategy.doMarketing(marketingPO.getInputVal());
            }
            System.out.println("doMarketingJob end =============");
            return true;
        }
        System.out.println("doMarketingJob setting is empty ===========");
        return false;
    }
}
复制代码


具体的思路就和策略模式有点类似:


策略模式


模式定义:定义一系列算法,将每个算法都封装起来,并且它们可以互换。策略模式是一种对象行为模式。


例如下图:


网络异常,图片无法展示
|


最后为了方便测试,我在工程里面引入了spring-context的依赖:


<!-- 关于spring的核型模块代码       -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
复制代码


测试的入口代码:


/**
 * @Author idea
 * @Date created in 10:14 上午 2020/5/4
 */
public class ApplicationDemo {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.scan("com.sise.idea.present");
        //启动上下文
        applicationContext.refresh();
        IMarketingCoreService marketingCoreService = applicationContext.getBean(MarketingCoreService.class);
        marketingCoreService.doMarketingJob("p111");
    }
}
复制代码


最后根据规则,通过产品编码来搜索到指定的营销手段,并执行对应的程序逻辑:


网络异常,图片无法展示
|


设计不足点


文章上边我曾经提及过,没有完美点代码,只有随着业务需求不断变化的设计思路,因此在真正落地整套营销系统的时候,还需要额外考虑很多的要素。例如说目前的这种设计只能满足于针对单个产品层面,如果以后有出现针对完整订单层面(例如说总支付订单满xxx元,享受xxx优惠)的还需要额外去思考,加上不同的营销手段之间是否有出现互斥的场景都是会有可能遇到的情况。


设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。文中我并没有过多地去讲解什么是xx模式,但是当通过某种较为灵活的方式来实现某样功能时,可能就已经使用了设计模式。


关于本案例的完整demo地址如下:

https://gitee.com/IdeaHome_admin/design_pattern/tree/master/design-model/src/main/java/com/sise/%E7%AD%96%E7%95%A5%E


目录
相关文章
|
消息中间件 Java 数据库
RocketMQ实战—9.营销系统代码初版
本文主要介绍了实现营销系统四大促销场景的代码初版:全量用户推送促销活动、全量用户发放优惠券、特定用户推送领取优惠券消息、热门商品定时推送。
RocketMQ实战—9.营销系统代码初版
|
消息中间件 搜索推荐 调度
RocketMQ实战—8.营销系统业务和方案介绍
本文详细介绍了电商营销系统的业务流程、技术架构及挑战解决方案。涵盖核心交易与支付后履约流程,优惠券和促销活动的发券、领券、用券、销券机制,以及会员与推送的数据库设计。技术架构基于Nacos服务注册中心、Dubbo RPC框架、RocketMQ消息中间件和XXLJob分布式调度工具,实现系统间高效通信与任务管理。针对千万级用户量下的推送和发券场景,提出异步化、分片处理与惰性发券等优化方案,解决高并发压力。同时,通过RocketMQ实现系统解耦,提升扩展性,并利用XXLJob完成爆款商品推荐的分布式调度推送。整体设计确保系统在大规模用户场景下的性能与稳定性。
RocketMQ实战—8.营销系统业务和方案介绍
|
消息中间件 NoSQL Java
RocketMQ实战—10.营销系统代码优化
本文主要介绍了如何对营销系统的四大促销场景的代码进行优化,包括:全量用户推送促销活动、全量用户发放优惠券、特定用户推送领取优惠券消息、热门商品定时推送。
|
数据采集 监控 并行计算
基于MCMC的贝叶斯营销组合模型评估方法论: 系统化诊断、校准及选择的理论框架
贝叶斯营销组合建模(Bayesian Marketing Mix Modeling,MMM)作为一种先进的营销效果评估方法,其核心在于通过贝叶斯框架对营销投资的影响进行量化分析。
622 3
基于MCMC的贝叶斯营销组合模型评估方法论: 系统化诊断、校准及选择的理论框架
|
人工智能 搜索推荐 Cloud Native
2025年企业营销的制胜指南:AI、Alpha世代与全渠道实战策略
2025年企业营销的制胜指南:AI、Alpha世代与全渠道实战策略
|
存储 NoSQL 算法
全链路营销|基于事件驱动的流程编排系统
本文主要介绍了 AE 策略中心的技术方案选型与落地实战。
|
数据可视化 搜索推荐 物联网
室内定位新突破:基于3D可视化与iBeacon技术的商场导航营销系统
**维小帮商场导航系统利用3D GIS、iBeacon定位、VR及物联网技术,提供3D导航、AR实景指引、设施查找及位置分享功能,提升顾客体验,增强商场品牌,推动经济效益增长。通过精准路径规划和沉浸式导航,用户能轻松找店,商场则塑造了智能形象,促进了交易量。**
720 1
室内定位新突破:基于3D可视化与iBeacon技术的商场导航营销系统
|
人工智能 分布式计算 架构师
大数据及AI典型场景实践问题之基于MaxCompute构建Noxmobi全球化精准营销系统如何解决
大数据及AI典型场景实践问题之基于MaxCompute构建Noxmobi全球化精准营销系统如何解决
|
前端开发 Java JSON
Struts 2携手AngularJS与React:探索企业级后端与现代前端框架的完美融合之道
【8月更文挑战第31天】随着Web应用复杂性的提升,前端技术日新月异。AngularJS和React作为主流前端框架,凭借强大的数据绑定和组件化能力,显著提升了开发动态及交互式Web应用的效率。同时,Struts 2 以其出色的性能和丰富的功能,成为众多Java开发者构建企业级应用的首选后端框架。本文探讨了如何将 Struts 2 与 AngularJS 和 React 整合,以充分发挥前后端各自优势,构建更强大、灵活的 Web 应用。
320 0
|
SQL 数据采集 算法
【电商数据分析利器】SQL实战项目大揭秘:手把手教你构建用户行为分析系统,从数据建模到精准营销的全方位指南!
【8月更文挑战第31天】随着电商行业的快速发展,用户行为分析的重要性日益凸显。本实战项目将指导你使用 SQL 构建电商平台用户行为分析系统,涵盖数据建模、采集、处理与分析等环节。文章详细介绍了数据库设计、测试数据插入及多种行为分析方法,如购买频次统计、商品销售排名、用户活跃时间段分析和留存率计算,帮助电商企业深入了解用户行为并优化业务策略。通过这些步骤,你将掌握利用 SQL 进行大数据分析的关键技术。
1375 0