策略模式:让你的代码灵活应对不同场景

写在前面

如果你正在为代码的可扩展性和可维护性感到烦恼,策略模式可以成为你的得力助手。本篇技术文章详细介绍了策略模式的核心原理和实战应用,帮助你解决在程序设计中所面临的挑战。无论你是初学者还是有一定经验的开发者,这篇文章都能够为你提供有益的知识和实用的技巧,值得一读!

前言

用于处理类或对象的组合的结构型的设计模式已经输出完毕:

适配器模式揭秘:让不兼容的组件完美协同

剖析装饰器模式:让你的代码更灵活、可扩展

探秘代理模式:核心原理与应用实践

优雅的程序设计:掌握门面模式的奥秘

桥梁模式:解耦抽象与实现的秘诀

组合模式揭秘:如何构建可扩展的树形结构

提升软件性能的秘密武器:揭秘实战中的享元模式

从这篇文章开始来盘一盘行为型设计模式,那么行为型的设计模式有哪些呢?行为型模式是用于描述类或对象怎样交互以及怎样分配职责,共十一种,包括策略模式、模版方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

什么是策略模式

策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式的主要目的是将算法的行为和环境分开,将一系列算法封装在策略类中,并在运行时根据客户端的需求选择相应的算法。策略模式适用于需要使用多种算法,且算法之间可以相互替换的情况。在策略模式中,算法的变化不会影响到使用算法的客户端。

策略模式的核心原理

策略模式是一种行为设计模式,其核心原理是将可以相互替换的算法封装成独立的类,并使它们能够互相之间替换,以使得算法的变化独立于使用算法的客户端。

策略模式主要包括三个核心角色:

  1. Context(上下文):这个角色是策略模式中的重要组成部分,通常用于存储和传递策略对象,以及处理策略对象的交互逻辑。上下文对象在客户端的请求下,会调用合适的策略对象来执行相应的操作。
  2. Strategy(策略):这个角色通常是一个接口,用于定义各种策略对象的共同方法。具体策略对象实现这个接口,并包含具体的算法实现。策略对象不持有任何上下文对象的状态,这样保证了策略对象的可复用性。
  3. ConcreteStrategy(具体策略):这个角色是实现策略接口的具体类,包含了具体的算法实现。具体策略对象通常会持有上下文对象的状态,以便在执行算法时能够访问和修改这些状态。

这三个核心角色共同实现了策略模式的核心思想:将算法与使用算法的客户端分离,使算法可以独立于客户端而变化。

策略模式如何实现

需求描述

很多购物网站都有会员业务,不同等级的会员可以享受不同程度的优惠,这里假设某会员业务系统的会员等级有非会员、初级会员、中级会员、高级会员四个等级,其中非会员在支付的时候需要全额支付 ,初级会员可以享受8折优惠,中级会员可以享受7折优惠,高级会员可以享受5折优惠,如果需要写一个支付接口,需要怎么实现呢?

实现方案

类似这样的业务模型,是比较适合使用策略模式的,但是如果仅仅使用策略模式是没有办法在主业务流程中完全避免if else的判断的,如果从实际业务出发,可以把简单工厂模式和策略模式结合起来使用。策略模式只负责定义不同的优惠策略,而简单工厂模式,负责根据不同的会员,生产出不同的具体优惠策略。具体怎么做呢?

1、定义抽象的支付策略接口:PayStrategy.java;

java 复制代码
/**
 * 支付策略接口
 */
public interface PayStrategy {
    /**
     * 实际支付金额计算
     * @param money
     */
    Double compute(Double money);
}

2、定义具体的支付策略类:Level0Streategy.java、Level1Streategy.java、Level2Streategy.java、Level3Streategy.java

java 复制代码
/**
 * 非会员计费策略
 */
public class Level0Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("非会员开始计费");
        return money;
    }
}
java 复制代码
/**
 * 初级会员计费策略
 */
public class Level1Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("初级会员开始计费");
        return money*0.8;
    }
}
java 复制代码
/**
 * 中级会员计费策略
 */
public class Level2Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("中级会员开始计费");
        return money*0.7;
    }
}
java 复制代码
/**
 * 高级会员计费策略
 */
public class Level3Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("高级会员开始计费");
        return money*0.5;
    }
}

3、定义用于存储和传递策略的上下文:StreateContext.java

java 复制代码
/**
 * 支付策略上下文
 */
public class StrategyContent {
    private PayStrategy payStrategy;

    public StrategyContent(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    /**
     * 支付方法
     * @param money
     * @return
     */
    public Double pay(Double money){
        return this.payStrategy.compute(money);
    }
}

4、定义策略工厂类,用于生产具体的策略:PayStreategyFactory.java

java 复制代码
/**
 * 策略工厂
 */
public class PayStrategyFactory {

    public static PayStrategy getStrategy(Member member){
        PayStrategy payStrategy;
        switch (member.getLevel()){
            case "初级":
                payStrategy=new Level1Strategy();
                break;
            case "中级":
                payStrategy=new Level2Strategy();
                break;
            case "高级":
                payStrategy=new Level3Strategy();
                break;
            default:
                payStrategy=new Level0Strategy();
                break;
        }
        return payStrategy;
    }
}

5、编写客户端:,模拟不同的用户进行支付:Test.java

java 复制代码
@Data
@AllArgsConstructor
public class Member {
    /**
     * 会员姓名
     */
    private String name;
    /**
     * 会员等级:非会员、初级、中级、高级
     */
    private String level;
    /**
     * 支付金额
     */
    private Double pay;
}
java 复制代码
public class Test {
    public static void main(String[] args) {
        Member member = new Member("小明", "初级", 100.00);
        PayStrategy strategy = PayStrategyFactory.getStrategy(member);
        StrategyContent strategyContent = new StrategyContent(strategy);
        Double pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("小红", "中级", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("铁蛋", "高级", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("李刚", "非会员", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
    }
}

策略模式的适用场景

  1. 不同业务逻辑:在同一个业务逻辑中,可能会存在不同的策略或算法。例如,在电商网站中,可以根据不同的促销策略对商品进行不同的定价。在这种情况下,可以使用策略模式来封装不同的促销策略,并在运行时根据需要选择合适的策略。
  2. 数据排序策略:在处理大量数据时,可能需要使用不同的排序算法。例如,冒泡排序、选择排序、插入排序和二叉树排序等。在这种情况下,可以使用策略模式来定义不同的排序策略,并在运行时根据需要选择合适的策略。
  3. 算法切换:在某些情况下,可能需要根据不同的条件切换不同的算法。例如,在进行实时计算时,可能需要根据不同的输入数据选择不同的计算算法。在这种情况下,可以使用策略模式来封装不同的算法,并在运行时根据需要选择合适的算法。
  4. 行为切换:在系统中,可能需要根据不同的条件切换不同的行为。例如,在一个游戏中,可能需要根据不同的关卡选择不同的游戏策略。在这种情况下,可以使用策略模式来封装不同的游戏策略,并在运行时选择合适的行为。

总之,策略模式的应用场景非常广泛,可以用于处理不同业务逻辑、数据排序、算法切换和行为切换等方面。通过使用策略模式,我们可以将算法或行为的变化和具体实现细节分离出来,使得代码更加灵活、易于维护和扩展。

总结

优点:

  1. 避免使用多重条件语句:策略模式通过使用策略类和上下文对象来避免使用多重条件语句,如if-else语句或switch-case语句。通过将算法的行为封装到策略类中,并在运行时根据客户端的需求选择相应的算法,策略模式使得代码更加简洁、易于维护和扩展。
  2. 提供可重用的算法族:策略模式通过定义抽象策略类和具体策略类,提供了一系列的算法实现。这些算法可以在不同的上下文中重复使用,通过组合和替换不同的策略对象来满足客户端的需求。
  3. 分离算法和客户端:策略模式将算法的实现和使用分离到具体的策略类和上下文对象中。客户端只需要与上下文对象进行交互,而不需要直接处理算法的实现细节。这种分离使得代码更加清晰、易于理解和维护。
  4. 支持对开闭原则的完美支持:策略模式可以在不修改原有代码的情况下,灵活地增加新的算法。通过定义新的策略类和上下文对象,可以轻松地将新的算法集成到现有系统中,满足新的需求。
  5. 将算法的使用放到环境类中:策略模式将算法的使用放到上下文对象中,而算法的实现则移到具体策略类中。这种分离使得代码更加清晰、易于管理和扩展。
  6. 客户端必须理解所有策略算法的区别:策略模式要求客户端必须理解所有可用的策略算法的区别,以便在适当的时候选择合适的算法。这可能增加了客户端的复杂性和学习成本。

缺点

  1. 可能导致过多的策略类:策略模式可能导致创建过多的策略类,每个算法都对应一个策略类。这可能会增加系统的复杂性和维护成本。

总之,策略模式是一种行为型设计模式,它通过封装一系列可重用的算法实现,并将它们组合到不同的上下文中,实现了算法的行为和使用的分离。这种模式使得代码更加灵活、易于维护和扩展,同时支持在不修改原有代码的情况下增加新算法,从而提高了代码的灵活性和可维护性。

写在最后

感谢您阅读我们的技术文章!这篇文章详细介绍了策略模式的核心原理和实战应用,对于程序设计中所面临的问题提出了有益的解决方案。如果您觉得这篇文章有价值,请帮忙点赞和收藏,让更多人看到并受益。您的支持是我不断前行的动力和鼓励。再次感谢您的阅读和支持,期待我们的下一次相遇!

相关推荐
独自破碎E10 分钟前
Java是怎么实现跨平台的?
java·开发语言
To Be Clean Coder17 分钟前
【Spring源码】从源码倒看Spring用法(二)
java·后端·spring
xdpcxq102936 分钟前
风控场景下超高并发频次计算服务
java·服务器·网络
想用offer打牌39 分钟前
你真的懂Thread.currentThread().interrupt()吗?
java·后端·架构
橘色的狸花猫1 小时前
简历与岗位要求相似度分析系统
java·nlp
独自破碎E1 小时前
Leetcode1438绝对值不超过限制的最长连续子数组
java·开发语言·算法
用户91743965391 小时前
Elasticsearch Percolate Query使用优化案例-从2000到500ms
java·大数据·elasticsearch
程序员NEO1 小时前
LangChain4j 工具调用实战
后端
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue小区人脸识别门禁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
yaoxin5211231 小时前
279. Java Stream API - Stream 拼接的两种方式:concat() vs flatMap()
java·开发语言