策略模式在数据接收和发送场景的应用

简介: 策略模式在数据接收和发送场景的应用



在本篇文章中,我们介绍了策略模式,并在数据接收和发送场景中使用了策略模式。



背景

在最近项目中,需要与外部系统进行数据交互,刚开始交互的系统较为单一,刚开始设计方案时打算使用了if else 进行判断:

if("A".equals(system)){
    ASystem.sync("向A同步数据");
}
if("B".equals(system)){
    BSystem.sync("向B同步数据");
}
...


升级为策略模式


这样设计有什么样的问题呢?首先随着外部系统接入越来越多,不具备良好的扩展性,会导致代码越来越臃肿,其次从软件的设计角度来看, 不符合单一职责原则, 也不符合开闭原则。


那么选择什么样的设计模式来解决if else 堆砌的问题呢?首先我想到了策略模式。


首先我们来看一下策略模式的定义:

策略模式(Strategy Pattern)定义了一组同类型的算法,在不同的类中封装起来,每种算法可以根据当前场景相互替换,从而使算法的变化独立于使用它们的客户端(即算法的调用者)


那么代入到我们的需求场景,我需要向外部系统同步或接收数据,数据的类型决定了我需要同步给A系统或者B系统,这些不同的数据决定了不同的策略


策略模式的结构通常包括以下组成部分:

  1. 定义一个策略接口或抽象类:该接口或抽象类定义了所有策略类都需要实现的方法。
  2. 创建多个具体的策略类:每个具体的策略类都实现了策略接口或抽象类,并提供了不同的实现。
  3. 创建一个策略上下文类:该类负责使用策略,它通常会维护一个策略接口或抽象类的引用。
  4. 在客户端代码中使用策略上下文类:客户端代码可以根据需要选择不同的策略。


看定义有些抽象,下面的结构图应该会容易理解一些。



根据上面的结构,我们来实现一下我们的场景1.我们需要定义一个策略接口,定义与外部系统间交互都需要实现的方法


public interface DataProcessingStrategy {
    void receiveData();
    void sendData();
}


2.为每个外部系统创建一个策略类:

public class ASystemDataProcessingStrategy implements DataProcessingStrategy {
    @Override
    public void receiveData() {
        // 接收数据的具体实现
    }
    @Override
    public void sendData() {
        // 发送数据的具体实现
    }
}

public class BSystemDataProcessingStrategy implements DataProcessingStrategy {
    @Override
    public void receiveData() {
        // 接收数据的具体实现
    }
    @Override
    public void sendData() {
        // 发送数据的具体实现
    }
}


3.创建一个选择外部系统的策略类,用于在运行时根据需要选择合适的策略类

public class Context {
    private DataProcessingStrategy strategy;
    public Context(DataProcessingStrategy strategy) {
        this.strategy = strategy;
    }
    public void setStrategy(DataProcessingStrategy strategy) {
        this.strategy = strategy;
    }
    public void sendData(String data) {
        strategy.sendData(data);
    }
    public String receiveData() {
        return strategy.receiveData();
    }
}


4.最后,在需要调用外部系统同步数据的地方实例化相关策略类和上下文类,并调用executeStrategy方法:


public class Main {
    public static void main(String[] args) {
        // 创建两个策略对象
        DataProcessingStrategy strategyA = new ASystemDataProcessingStrategy();
        DataProcessingStrategy strategyB = new BSystemDataProcessingStrategy();
        // 创建上下文对象,并传入策略对象
        Context context = new Context(strategyA);
        //使用 ASystemDataProcessingStrategy 请求和接收数据
        context.sendData("");  
        context.receiveData("");
        // 使用 BSystemDataProcessingStrategy 请求和接收数据
        context = new Context(strategyB);
        context.sendData("");  
        context.receiveData("");
    }
}


升级为策略模式+工厂模式


那么策略模式存在什么样的问题呢?

  1. 硬编码的依赖关系:在上述代码中,我们直接将具体的策略类(例如StrategyA和StrategyB)硬编码到上下文类(Context)中。这意味着如果我们想要添加或修改策略,我们需要在上下文类中修改代码。这种硬编码的方式使得系统难以扩展和维护。
  2. 客户端与策略的具体实现紧密耦合:由于上下文类Context直接依赖于具体的策略类,因此客户端代码必须了解每个具体策略的细节。这增加了客户端代码的复杂性,并使得客户端代码与策略的具体实现紧密耦合,增加了代码的维护难度。


我们可以使用工厂模式来改进我们的设计。工厂模式可以帮助我们将对象的创建和使用过程分离,使得上下文类和客户端代码不需要了解具体策略的细节,那么我们来修改一下我们的实现:

// 策略接口和具体的策略类保持不变
public interface DataProcessingStrategy {
    void sendData(String data);
    String receiveData();
}
public class ASystemDataProcessingStrategy implements DataProcessingStrategy {
    @Override
    public void sendData(String data) {
        // 发送数据到系统A的实现
    }
    @Override
    public String receiveData() {
        // 从系统A接收数据的实现
    }
}
public class BSystemDataProcessingStrategy implements DataProcessingStrategy {
    @Override
    public void sendData(String data) {
        // 发送数据到系统B的实现
    }
    @Override
    public String receiveData() {
        // 从系统B接收数据的实现
    }
}
public class DataProcessingStrategyFactory {
   private static ConcurrentHashMap<String, DataProcessingStrategy> strategies = new ConcurrentHashMap<>();
   /**
    * 注册策略
    * @param strategyName
    * @param strategy
    */
   public static void register(String strategyName, DataProcessingStrategy strategy) {
       strategies.put(strategyName, strategy);
  }
   public static DataProcessingStrategy getStrategy(String strategyName) {
       return strategies.get(strategyName);
  }
}
//client类相关修改
public class Main {
    public static void main(String[] args) {
        DataProcessingStrategy systemA = DeployStrategyFactory.getStrategy("A");
        //使用 ASystemDataProcessingStrategy 请求和接收数据
        systemA.sendData("");  
        systemA.receiveData("");
        DataProcessingStrategy systemB = DeployStrategyFactory.getStrategy("B");
        // 使用 BSystemDataProcessingStrategy 请求和接收数据
        systemB.sendData("");  
        systemB.receiveData("");
    }
}


总结

在本篇文章中,我们介绍了策略模式,并在数据接收和发送场景中使用了策略模式。通过使用策略模式,我们可以在客户端代码中根据运行时条件动态地选择一个具体的策略类,并通过这个策略类来改变对象的行为。这样,我们就可以实现不同的数据接收和发送方式,而不需要在客户端代码中进行大量的if-else判断。同时通过策略模式+工厂模式的方式解决了客户端代码与策略的具体实现紧密耦合的问题。当然结合实际的场景灵活运用相应的设计模式也非常重要,避免过度设计。


团队介绍

我们是淘天集团-天猫奢品技术团队。天猫奢品汇聚全球顶尖品牌,覆盖全品类的高质量生活方式,致力于打造奢侈品线上消费首选平台。依托淘宝天猫电商生态,不断探索契合奢侈品品牌的互联网新体验技术与解决方案,以更加智能、友好的科技帮助品牌更好的经营,让用户享受更好的消费体验。


相关文章
|
存储 设计模式 算法
DDD之于业务支撑的意义
DDD之于业务支撑的意义
348 0
|
设计模式 算法 Java
关于编程模式的总结与思考(上)
关于编程模式的总结与思考(上)
186 0
|
XML Java Android开发
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
456 0
|
10月前
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
463 11
|
存储 设计模式 算法
如何在业务代码中优雅地使用责任链模式
如何在业务代码中优雅地使用责任链模式
380 1
|
存储 数据采集 前端开发
ClkLog 实践中的挑战:如何设计和实施有效的埋点指标
前端数据埋点要怎么做才能获取到有用的数据并对运营产生积极的作用,对于首次实施埋点及数据分析的工程师来说确实是个难点。网上很多文章讲的都是方法论和理论知识,真正实践的内容比较少,我们从一个案例来描述一下埋点要如何做。
ClkLog 实践中的挑战:如何设计和实施有效的埋点指标
|
缓存 移动开发 监控
淘宝页面首帧优化的经验和心得
淘宝页面首帧优化的经验和心得
574 9
|
SQL 安全 Java
慢SQL治理经验总结
慢SQL治理经验总结
778 0
|
存储 Web App开发 运维
一种业务中台建设的方法
## 一、中台建设的复杂性 ### 1.1 中心、平台、中台的演进 应用架构一般演进的规律是,从中心应用演进成平台应用,然后从平台应用演进成中台应用,演进背后的底层逻辑就是"降本增效",降本增效在软件架构中经常被提到,本是成本的意思,效是效率的意思,连起来就是降低成本提升效率,仅仅回答到这一层,还是有些抽象,这里"本"包含了哪些成本?"效"又包含了哪些效率? 软件开发的成本包含了:分析成本、沟通
2760 0
一种业务中台建设的方法
|
设计模式 Java 中间件
好好的“代码优化”是怎么一步步变成“过度设计”的(下)
好好的“代码优化”是怎么一步步变成“过度设计”的(下)
263 5