带你走进不一样的策略模式

简介: 带你走进不一样的策略模式

前言

在编程的世界里,每一次按键都是在与代码做策略游戏。我们试图在效率、灵活性和可维护性之间找到平衡点。今天,我们要探讨的是Java中的策略模式,这个模式就像是一个老练的军师,让我们在面对不断变化的需求时能够灵活调整战略。在本文中,我们不仅要学习策略模式的理论,更要通过实战将这个强大的工具纳入我们的编程武库。准备好了吗?让我们开始这场精彩的策略之旅吧

策略模式简介

策略模式(Strategy Pattern)是一种设计模式,它使得一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

概念解释

策略(Strategy):一个策略代表了一个算法,或者说是一个行为。在策略模式中,我们可以定义一系列算法或行为,并将每一个算法封装到具有共同接口的独立的类中。

上下文(Context):上下文是使用策略的对象。通常,它会持有一个指向策略对象的引用,并可通过该引用调用策略对象实现的算法。上下文可能会定义一个接口来让策略对象访问它的数据。

策略接口(Strategy Interface):这是一个定义每个策略或算法必须遵守的接口。它是一个共同的接口,让上下文能够在不同策略之间切换而不影响客户端。

具体策略(Concrete Strategies):实现策略接口的类,提供具体的算法或行为。

策略模式的结构

Strategy(策略接口):定义所有支持的算法的公共接口。Context 使用这个接口来调用 ConcreteStrategy 定义的算法。

ConcreteStrategy(具体策略):实现 Strategy 接口的具体类。每一个 ConcreteStrategy 提供了一个算法或行为。

Context(上下文):持有一个对 Strategy 对象的引用。它可以定义一个接口来让 Strategy 访问它的数据。

// 策略接口
public interface Strategy {
    public void execute();
}
// 具体策略A
public class ConcreteStrategyA implements Strategy {
    public void execute() {
        System.out.println("执行策略A");
    }
}
// 具体策略B
public class ConcreteStrategyB implements Strategy {
    public void execute() {
        System.out.println("执行策略B");
    }
}
// 上下文
public class Context {
    private Strategy strategy;
    // 构造方法,传入策略对象
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    // 上下文接口
    public void executeStrategy() {
        strategy.execute();
    }
}
// 客户端代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStrategyA()); // 使用策略A
        context.executeStrategy(); // 输出:执行策略A
        context = new Context(new ConcreteStrategyB()); // 使用策略B
        context.executeStrategy(); // 输出:执行策略B
    }
}

策略模式优点

策略模式是一种常用的设计模式,它提供了一系列显著的优点,特别是在处理算法、行为或策略需要在运行时可更换的场景中。以下是策略模式的一些主要优点:

  1. 代码复用与分离
    策略模式通过将算法封装在独立的策略类中,实现了算法的复用。这种封装也促进了算法逻辑和使用算法的客户端代码之间的分离。每个策略类负责自己的算法,使得算法的管理和维护变得更加清晰和简单。
  2. 易于扩展
    策略模式使得添加新的策略或算法变得非常容易,而不需要修改现有的代码。这是因为策略模式提供了一个共同的接口给所有的策略类,任何新的策略实现都可以通过实现这个接口加入到系统中,而不会影响到使用策略的客户端代码。这种易于扩展的特性使得系统更加灵活,能够更好地适应变化。
  3. 替换继承
    在一些情况下,使用策略模式可以避免使用继承来提供类的不同行为。在传统的面向对象设计中,继承被广泛用于扩展类的功能。然而,继承有其固有的缺点,如可能导致类层次结构变得复杂,以及子类与父类之间的紧密耦合。策略模式提供了一种替代继承的方法,通过组合的方式(即在类中引入策略对象)来改变类的行为,这样做可以提高类的灵活性和可维护性。
  4. 更好的测试性
    由于策略模式将算法的实现从其使用环境中分离出来,测试各个算法变得更加容易。每个策略类可以独立于上下文进行单元测试,这有助于识别和修复潜在的算法错误,提高代码的质量。
  5. 更好的控制算法族
    在策略模式中,所有相关的算法族都被封装在一个定义良好的策略接口后面。这不仅使得算法的管理变得容易,而且还可以在运行时动态地在不同算法之间进行切换,为客户端代码提供了更大的灵活性和控制力。
    综上所述,策略模式通过提供一种机制来分离和封装算法或行为,使得代码更加模块化、易于扩展和维护,同时也提高了代码的复用性和灵活性。这些优点使得策略模式在众多设计模式中占有一席之地。

项目实践之bean策略

构思业务

现在我有一个业务它需要根据某一个判断条件(类型)来选择调用某一bean中的相关方法,传统的实现方式如下图

对于上面的方式,会存在这样一个问题,每当我新加一个类型,就要新加一个service实现。并且我的业务中要新加判断,如果我这个业务中存在一个方法会新加一个,如果是100个可能就会新加100个。这样不仅违法了开闭原则,而且还有冗余代码且改起来费时间,最终演变为策略模式,如下图

策略实现

策略接口实现
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
 * @author xiaobo
 */
public interface IDataStrategy {
    /**
     * description: 判断是否有值
     *
     * @param mainType 主要类型
     * @return boolean
     * @date 2024/4/19 15:57
     */
    boolean supports(String mainType);
}
策略上下文
package com.jxth.dasmart.bridge.configs;
import com.jxth.dasmart.bridge.modules.mid.IMidDataStrategy;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * description: 策略管理
 *
 * @author bo
 * @version 1.0
 * @date 2024/4/19 16:10
 */
@Component
@RequiredArgsConstructor
public class DataServiceManager {
    private final List<IMidDataStrategy> services;
    public IMidDataStrategy getService(String mainType) {
        return services.stream()
                .filter(service -> service.supports(mainType))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("No suitable service found for mainType: " + mainType));
    }
}
业务实现
public class BusinessTest {
  @Resource
  protected DataServiceManager serviceManager;
  public void test(String type){
    IDataStrategy service = serviceManager.getService(type);
    // 实现相关方法
  }
}


相关文章
|
6月前
|
设计模式 Java 开发者
设计模式揭秘:Java世界的七大奇迹
【4月更文挑战第7天】探索Java设计模式:单例、工厂方法、抽象工厂、建造者、原型、适配器和观察者,助你构建健壮、灵活的软件系统。了解这些模式如何提升代码复用、可维护性,以及在特定场景下的应用,如资源管理、接口兼容和事件监听。掌握设计模式,但也需根据实际情况权衡,打造高效、优雅的软件解决方案。
45 0
|
6月前
|
设计模式 存储 Java
设计模式:循序渐进走入工厂模式
设计模式:循序渐进走入工厂模式
|
6月前
|
设计模式 算法
【设计模式】阿里终面:你觉得这个例子是策略模式吗?
【设计模式】阿里终面:你觉得这个例子是策略模式吗?
57 1
|
设计模式 Java
【设计模式系列】——观察者模式攻坚战
【设计模式系列】——观察者模式攻坚战
241 1
【设计模式系列】——观察者模式攻坚战
|
设计模式 NoSQL Java
被误读的设计模式
被误读的设计模式
121 0
被误读的设计模式
|
Dubbo Java 应用服务中间件
炫技?No? only 策略模式
Autowire作用于方法时Spring会先实例化所有Bean,然后根据配置进行扫描,当检测到@Autowired后进行注入,注入时调用这个方法,也就是当启动完容器,map已经存放了实体类映射关系。
97 0
炫技?No? only 策略模式
Zp
初尝策略模式~真香
初尝策略模式~真香
Zp
140 0
|
设计模式 数据采集 算法
还记得设计模式中称霸武林的的六大设计原则吗?
设计模式中称霸武林的的六大设计原则
136 0
还记得设计模式中称霸武林的的六大设计原则吗?
|
设计模式 Java
设计模式铺铺路(面向对象设计的原则一二)
我们的知识星球马上就要开始更新设计模式了,在更新设计模式之前,我们是不是需要做一些准备呢?否则设计模式中一些遵循的原则大家会一头雾水,所以我今天来给大家说一些面向对象的七种原则,有人说是6种有人说是7种,我个人认为是7种,我就按照7种来说,今天我就介绍2种,下一篇文章将会继续介绍剩下的五种原则,这些原则也会在设计模式中出现,各位技术人,欢迎大家的踊跃参加呦。
设计模式铺铺路(面向对象设计的原则一二)
|
设计模式 算法 程序员
程序员的修仙之路——设计模式六大基本原则
程序员的修仙之路——设计模式六大基本原则
178 0
下一篇
无影云桌面