当前位置:首页 > 科技  > 软件

一文搞懂设计模式—策略模式

来源: 责编: 时间:2024-02-01 12:52:11 289观看
导读在软件开发中,经常会遇到需要根据不同的条件来实现不同行为的场景。这种场景下,策略模式(Strategy Pattern)就是一种非常有用的设计模式。策略模式属于行为型模式,允许我们定义一系列算法,并将其封装在独立的策略类中,使得它

在软件开发中,经常会遇到需要根据不同的条件来实现不同行为的场景。这种场景下,策略模式(Strategy Pattern)就是一种非常有用的设计模式。KtG28资讯网——每日最新资讯28at.com

策略模式属于行为型模式,允许我们定义一系列算法,并将其封装在独立的策略类中,使得它们可以互相替换。通过使用策略模式,我们能够灵活地选择和切换不同的算法,而无需修改原有的代码,替代⼤量 if else 的逻辑。KtG28资讯网——每日最新资讯28at.com

使用场景

策略模式通常在以下情况下被使用:KtG28资讯网——每日最新资讯28at.com

  • 当存在多种实现方式,且需要在运行时动态选择具体实现时,策略模式非常有用。例如,一个购物应用可能需要根据用户的会员等级来计算折扣,不同等级对应不同的计算方式,这时就可以使用策略模式来实现。
  • 当存在一组类似的行为,只是实现细节略有不同,但又不希望通过继承来添加新的子类时,策略模式也很适用。它将这组行为封装在独立的策略类中,并通过委托的方式在上下文对象中使用。

例如:KtG28资讯网——每日最新资讯28at.com

  • 支付方式选择:一个电子商务平台可以根据用户的选择来使用不同的支付策略,例如信用卡支付、支付宝支付、微信支付等。
  • 排序算法选择:一个排序工具可以根据用户的需求选择不同的排序算法,例如快速排序、归并排序等。
  • 数据验证:一个表单验证工具可以根据不同的验证规则采用不同的验证策略,例如长度验证、格式验证等。

这些只是策略模式的一些例子,实际应用场景非常丰富。通过使用策略模式,我们可以将算法或行为与具体的业务逻辑解耦,使得系统更加灵活和可扩展。KtG28资讯网——每日最新资讯28at.com

策略模式实现

在策略模式中,有三个核心角色:上下文(Context)、策略接口(Strategy)和具体策略类(Concrete Strategy)。KtG28资讯网——每日最新资讯28at.com

  • 上下文(Context):封装了具体策略的执行逻辑,提供给客户端使用的接口。上下文通常包含一个指向策略接口的引用,用于调用具体策略的方法。
  • 策略接口(Strategy):定义了一组算法或行为的公共接口,所有具体策略都必须实现该接口。
  • 具体策略类(Concrete Strategy):实现了策略接口,提供了具体的算法或行为。

下面我们来实现一下策略模式:KtG28资讯网——每日最新资讯28at.com

步骤 1

创建策略接口。KtG28资讯网——每日最新资讯28at.com

//策略接口public interface PaymentStrategy {    void pay(double amount);}

步骤2

创建策略接口实现类。KtG28资讯网——每日最新资讯28at.com

//具体策略类public class CreditCardPayment implements PaymentStrategy {    public void pay(double amount) {        System.out.println("使用信用卡支付:" + amount);        // 具体的支付逻辑    }}
public class WeChatPay implements PaymentStrategy {    public void pay(double amount) {        System.out.println("使用微信支付:" + amount);        // 具体的支付逻辑    }}

注意:在实际项目中,我们一般通过工厂方法模式来实现策略类的声明。KtG28资讯网——每日最新资讯28at.com

实现关系如下:KtG28资讯网——每日最新资讯28at.com

图片图片KtG28资讯网——每日最新资讯28at.com

步骤 3

创建 Context 类。KtG28资讯网——每日最新资讯28at.com

// 上下文类public class PaymentContext {    private PaymentStrategy paymentStrategy;        public PaymentContext(PaymentStrategy paymentStrategy) {        this.paymentStrategy = paymentStrategy;    }        public void pay(double amount) {        paymentStrategy.pay(amount);    }}

调用一下:KtG28资讯网——每日最新资讯28at.com

// 使用示例public class Main {    public static void main(String[] args) {        PaymentStrategy strategy = new CreditCardPayment();        PaymentContext context = new PaymentContext(strategy);        context.pay(100.0);                strategy = new WeChatPay();        context = new PaymentContext(strategy);        context.pay(200.0);    }}

输出:KtG28资讯网——每日最新资讯28at.com

使用信用卡支付:100.0使用微信支付:200.0

在上面的代码中,我们定义了一个 PaymentStrategy 接口作为策略接口,两个具体的策略类 CreditCardPayment 和 WeChatPay 实现了该接口。然后,我们创建了一个 PaymentContext 上下文对象,并根据需要传入不同的策略实例进行支付操作。KtG28资讯网——每日最新资讯28at.com

策略模式的优缺点

策略模式的优点包括:KtG28资讯网——每日最新资讯28at.com

  • 松耦合:策略模式将不同的策略封装在独立的类中,与上下文对象解耦,增加了代码的灵活性和可维护性。
  • 易于扩展:可以通过添加新的策略类来扩展系统的功能,无需修改现有代码。
  • 符合开闭原则:对于新的策略,无需修改上下文对象,只需要实现新的策略接口即可。

策略模式的缺点包括:KtG28资讯网——每日最新资讯28at.com

  • 类数量增多:每个具体策略都需要一个独立的类,如果策略较多,将导致类的数量增加。
  • 上层必须知道所有策略类:上层模块必须知道有哪些策略,并选择合适的策略进行使用,这与迪米特法则是相违背的,我只是想使用了一个策略,我凭什么就要了解这个策略呢?那要你的封装类还有什么 意义?这是原装策略模式的一个缺点。

注意事项: 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题,否则日后的系统维护就会成为一个烫手山芋。KtG28资讯网——每日最新资讯28at.com

策略模式优化

使用Map取消 Context 类

我们可以将策略实现类放进 Map 中,根据 key 去选择具体的策略,就不必事先定义 Context 类。KtG28资讯网——每日最新资讯28at.com

public static void main(String[] args) {        Map<String, PaymentStrategy> map=new HashMap<>();        map.put("CREDIT_CARD", new CreditCardPayment());        map.put("WECHAT_PAY",new WeChatPay());        map.get("CREDIT_CARD").pay(100.0);        map.get("WECHAT_PAY").pay(200.0);    }

策略枚举解决策略类膨胀

策略枚举可以解决策略类过多的问题。KtG28资讯网——每日最新资讯28at.com

我们对原装的策略模式进行改造,把原有定义在抽象策略中的方法移植到枚举中,让枚举成员成为一个具体策略。KtG28资讯网——每日最新资讯28at.com

@Slf4jpublic enum PaymentStrategyEnum {    CREDIT_CARD {        @Override        public void pay(double amount) {            log.info("使用信用卡支付:" + amount);            // 具体的支付逻辑        }    },    WECHAT_PAY {        @Override        public void pay(double amount) {            log.info("使用微信支付:" + amount);            // 具体的支付逻辑        }            };    public abstract void pay(double amount);}

在上面的代码中,我们定义了一个枚举类型 PaymentStrategy,其中包含两个枚举常量 CREDIT_CARD 和 WECHAT_PAY。每个枚举常量都重写了 pay() 方法,用于具体的支付逻辑。KtG28资讯网——每日最新资讯28at.com

// 使用示例public static void main(String[] args) {        Map<String, PaymentStrategyEnum> map=new HashMap<>();        map.put("CREDIT_CARD",  PaymentStrategyEnum.CREDIT_CARD);        map.put("WECHAT_PAY", PaymentStrategyEnum.WECHAT_PAY);        map.get("CREDIT_CARD").pay(100.0);        map.get("WECHAT_PAY").pay(200.0);    }

注意:策略枚举是一个非常优秀和方便的模式,但是它受枚举类型的限制,每个枚举项都是 public、final、static 的,扩展性受到了一定的约束,因此在系统开发中,策略枚举一般担当不经常发生变化的角色。KtG28资讯网——每日最新资讯28at.com

SpringBoot中的策略模式

SpringBoot中使用策略模式更加方便:KtG28资讯网——每日最新资讯28at.com

public interface Test {    void print(String name);}
@Service("testA")@Slf4jpublic class TestA implements Test{    @Override    public void print(String name) {        log.info("实现类A"+name);    }}
@Service("testB")@Slf4jpublic class TestB implements Test{    @Override    public void print(String name) {        log.info("实现类B"+name);    }}

使用的时候 @Autowired 或者 @Resource 即可,SpringBoot会帮我们把实现类自动注入注入Map。KtG28资讯网——每日最新资讯28at.com

@Resourceprivate Map<String,Test> map;
Test test = map.get("你想拿出的具体策略类");test.print("hello world");

总结

策略模式是一种强大而灵活的设计模式,它可以帮助我们处理不同的算法或行为,并使系统更具可维护性和扩展性。通过封装具体的策略类和使用上下文对象,我们可以轻松地选择和切换不同的策略,而无需修改现有的代码。KtG28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-70477-0.html一文搞懂设计模式—策略模式

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 深入理解Java线程池,剖析LinkedBlockingQueue源码实现

下一篇: Java中的并发编程模型及其应对策略

标签:
  • 热门焦点
  • 小米官宣:2023年上半年出货量中国第一!

    今日早间,小米电视官方微博带来消息,称2023年小米电视上半年出货量达到了中国第一,同时还表示小米电视的巨屏风暴即将开始。“公布一个好消息2023年#小米电视上半年出货量中国
  • 三言两语说透设计模式的艺术-简单工厂模式

    一、写在前面工厂模式是最常见的一种创建型设计模式,通常说的工厂模式指的是工厂方法模式,是使用频率最高的工厂模式。简单工厂模式又称为静态工厂方法模式,不属于GoF 23种设计
  • Rust中的高吞吐量流处理

    作者 | Noz编译 | 王瑞平本篇文章主要介绍了Rust中流处理的概念、方法和优化。作者不仅介绍了流处理的基本概念以及Rust中常用的流处理库,还使用这些库实现了一个流处理程序
  • 2023 年的 Node.js 生态系统

    随着技术的不断演进和创新,Node.js 在 2023 年达到了一个新的高度。Node.js 拥有一个庞大的生态系统,可以帮助开发人员更快地实现复杂的应用。本文就来看看 Node.js 最新的生
  • 服务存储设计模式:Cache-Aside模式

    Cache-Aside模式一种常用的缓存方式,通常是把数据从主存储加载到KV缓存中,加速后续的访问。在存在重复度的场景,Cache-Aside可以提升服务性能,降低底层存储的压力,缺点是缓存和底
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • 最“俊美”淘宝卖家,靠直播和短视频圈粉,上架秒光,年销3000万

    来源 | 电商在线文|易琬玉编辑|斯问受访店铺:Ringdoll戒之人形图源:微博@御座的黄山、&ldquo;Ringdoll戒之人形&rdquo;淘宝店铺有关外貌的评价,黄山已经听累了。生于1985年的他,哪
  • 四年持续更迭坚持探索行业无人之境,HarmonyOS 4带来五大升级多项创新

    除了华为每年新发布的旗舰手机系列,上亿花粉更加期待鸿蒙系统每次的跨版本大更新。8月4日,HarmonyOS 4于HDC 2023正式发布,这也是该系统历经四年的再
  • iQOO Neo8 Pro真机谍照曝光:天玑9200+和V1+旗舰双芯加持

    去年10月,iQOO推出了iQOO Neo7系列机型,不仅搭载了天玑9000+,而且是同价位唯一一款天玑9000+直屏旗舰,一经上市便受到了用户的广泛关注。在时隔半年后,
Top