【设计模式】 策略模式介绍及C代码实现

简介: 策略模式(Strategy Pattern)是一种常用的面向对象设计模式,它定义了一系列可互相替换的算法或策略,并将每个算法封装成独立的对象,使得它们可以在运行时动态地替换。具体来说,策略模式定义了一系列算法,每个算法都封装在一个具体的策略类中,这些策略类实现了相同的接口或抽象类。在使用算法的时候,客户端通过一个上下文对象来调用策略类的方法,从而完成算法的执行。这样,客户端可以在运行时动态地选择不同的策略类,从而实现不同的行为。

背景

  在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂,而且有时候支持不使用的算法也是一个性能负担。 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
   我们还是使用这个例子,比如你要从北京去上海出差,出差的工作是不变的,但是每次去使用的交通工具却有不同的方式,可能有火车、可能飞机、可能开车。如果写程序实现,我们就可以分别将不同的交通工具方式写到不同的类中,然后再代码运行时根据不同的交通方式调用不同类的对象,从而实现在一套代码中通过运行是的调用兼容不同交通工具方式的出差这个场景。 这种定义一系列可互相替换的算法,并且每个算法独立封装,然后再运行的时候动态替换的方式就是策略模式。

定义

  策略模式(Strategy Pattern)是一种常用的面向对象设计模式,它定义了一系列可互相替换的算法或策略,并将每个算法封装成独立的对象,使得它们可以在运行时动态地替换。

  具体来说,策略模式定义了一系列算法,每个算法都封装在一个具体的策略类中,这些策略类实现了相同的接口或抽象类。在使用算法的时候,客户端通过一个上下文对象来调用策略类的方法,从而完成算法的执行。这样,客户端可以在运行时动态地选择不同的策略类,从而实现不同的行为。

策略模式通常由三个角色组成:

  • 环境角色(Context):它是客户端代码所定义的一组接口或抽象类,表示一种算法或策略。
  • 抽象策略角色(Strategy):它是一个抽象类或接口,定义了一组算法或策略的接口。
  • 具体策略角色(Concrete Strategy):它是抽象策略的具体实现类,实现了策略角色定义的算法或策略。

应用场景

策略模式主要应用在以下场景:

  • 当你想使用对象中各种不同的算法变体, 并希望能在运行时切换算法时, 可使用策略模式。

  策略模式让你能够将对象关联至可以不同方式执行特定子任务的不同子对象, 从而以间接方式在运行时更改对象行为。

  • 当你有许多仅在执行某些行为时略有不同的相似类时, 可使用策略模式。

      策略模式让你能将不同行为抽取到一个独立类层次结构中, 并将原始类组合成同一个, 从而减少重复代码。

  • 如果算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来。

      策略模式让你能将各种算法的代码、 内部数据和依赖关系与其他代码隔离开来。 不同客户端可通过一个简单接口执行算法, 并能在运行时进行切换。

  • 当类中使用了复杂条件运算符以在同一算法的不同变体中切换时, 可使用该模式。

      策略模式将所有继承自同样接口的算法抽取到独立类中, 因此不再需要条件语句。 原始对象并不实现所有算法的变体, 而是将执行工作委派给其中的一个独立算法对象。

具体的应用场景包括:

  1. 订单价格计算:根据不同的促销活动(如会员折扣、团购活动、满减优惠等),可以使用不同的算法来计算订单的价格。
  2. 支付方式选择:根据不同的支付方式(如信用卡、支付宝、微信支付等),可以使用不同的算法来完成支付过程。
  3. 排序算法选择:根据不同的排序算法(如冒泡排序、快速排序、归并排序等),可以使用不同的算法来排序。
  4. 表单验证:根据不同的表单验证规则(如必填字段、长度限制、格式要求等),可以使用不同的算法来验证表单数据的有效性。

  在这些场景中,策略模式可以帮助我们将算法或策略的实现与算法或策略的使用分离开来,从而实现代码的复用、可维护性和灵活性。

模式结构

在这里插入图片描述

实现步骤

策略模式设的主要实现步骤:

  1. 定义一个策略接口或抽象类,该接口或抽象类声明了策略所需的方法,具体的策略类将实现这些方法。
  2. 定义具体的策略类,实现策略接口或抽象类中声明的方法。
  3. 定义一个上下文类,该类包含一个策略对象的引用,用于调用策略对象的方法。上下文类也可以定义一些辅助方法,用于支持策略的使用。
  4. 在客户端中,根据需要创建不同的策略对象,并将其传递给上下文对象。
  5. 在上下文对象中调用策略对象的方法,完成具体的算法或行为。

C语言代码示例

  其实设计模式是一种与编程语言无关的设计思想,但是其中很重要的思想就是面向对象,所以在面向对象的语言,比如C++、Java中实现起来就非常顺手,但因为我本人是C语言出身,并且作为主要编程语言的,所以就使用了C语言来实现模板方法的设计模式。

  在C语言中,由于没有面向对象的特性,策略模式的实现方式会略有不同。通常可以使用函数指针来模拟接口,使用函数指针变量来引用具体的策略函数。下面是一个简单的示例,演示了如何使用C语言实现策略模式:

#include <stdio.h>

// 1. 定义函数指针类型
typedef void (*Strategy)(int, int);

// 2. 定义具体的策略函数
void operation_add(int num1, int num2) {
    printf("%d + %d = %d\n", num1, num2, num1 + num2);
}

void operation_subtract(int num1, int num2) {
    printf("%d - %d = %d\n", num1, num2, num1 - num2);
}

void operation_multiply(int num1, int num2) {
    printf("%d * %d = %d\n", num1, num2, num1 * num2);
}

// 3. 定义上下文结构体
typedef struct {
    Strategy strategy;
} Context;

// 4. 在客户端中使用策略模式
int main() {
    Context context;

    // 使用加法策略
    context.strategy = operation_add;
    context.strategy(10, 5);

    // 使用减法策略
    context.strategy = operation_subtract;
    context.strategy(10, 5);

    // 使用乘法策略
    context.strategy = operation_multiply;
    context.strategy(10, 5);

    return 0;
}

  在上面的示例中,我们首先定义了一个函数指针类型 Strategy,该函数指针类型接受两个整型参数,并且没有返回值。接着定义了具体的策略函数 operation_add、operation_subtract 和 operation_multiply,这些函数都符合 Strategy 函数指针类型的定义。然后定义了上下文结构体 Context,该结构体包含一个函数指针类型的成员变量 strategy。最后,在 main 函数中创建一个上下文对象 context,并分别将不同的策略函数赋值给 context.strategy 成员变量,最终调用 context.strategy 函数指针来执行具体的策略函数。

  需要注意的是,由于C语言没有面向对象的特性,策略模式的实现方式相对于其他编程语言会更加笨拙,代码可读性也不太好。如果需要实现更复杂的策略模式,建议使用其他面向对象的编程语言来实现。

总结

  策略模式为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。并且策略模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要策略模式。如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

下面我们从设计原则的角度分析策略模式:

  • 开闭原则:策略模式可以在不修改原有代码的情况下添加、删除、切换不同的策略,因此可以有效地满足开闭原则。
  • 代码复用:不同的策略可以复用相同的代码,减少了代码冗余。
  • 单一职责原则:将不同的算法封装在不同的策略中,实现了单一职责原则。

策略模式的主要优点在于:

  1. 提高了代码的复用性:将算法封装在独立的策略类中,可以避免代码重复,提高了代码的复用性。
  2. 易于扩展和维护:由于算法的实现与算法的使用分离开来,所以在添加新的算法或修改现有算法时,不会影响到其他算法的实现和使用,易于扩展和维护。
  3. 提高了代码的灵活性:在运行时动态地选择不同的策略类,可以实现不同的行为,提高了代码的灵活性。

总之,策略模式是一种简单而有效的设计模式,可以帮助我们提高代码的复用性、可维护性和灵活性。

目录
相关文章
|
1月前
|
设计模式 算法 Kotlin
Kotlin - 改良设计模式 - 策略模式
Kotlin - 改良设计模式 - 策略模式
48 4
|
27天前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
43 1
|
1月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
29 2
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
47 2
|
2月前
|
设计模式 算法 数据库连接
PHP中的设计模式:提高代码的可维护性和扩展性
【10月更文挑战第13天】 本文将探讨PHP中常见的设计模式及其在实际项目中的应用。通过对比传统编程方式,我们将展示设计模式如何有效地提高代码的可维护性和扩展性。无论是单例模式确保类的单一实例,还是观察者模式实现对象间的松耦合,每一种设计模式都为开发者提供了解决特定问题的最佳实践。阅读本文后,读者将能更好地理解和应用这些设计模式,从而提升PHP编程的效率和质量。
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文通过游泳运动员的案例,介绍策略模式及其在Kotlin中的改良应用,利用高阶函数简化代码结构,提高灵活性。
39 3
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文介绍策略模式在Kotlin中的应用,通过游泳运动员的例子,展示如何使用接口和高阶函数实现策略模式,使代码更简洁、灵活。
34 2
|
2月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
67 3
|
2月前
|
设计模式 算法 Kotlin
Kotlin - 改良设计模式 - 策略模式
Kotlin - 改良设计模式 - 策略模式
|
2月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第12天】 在软件开发的世界中,设计模式是解决常见问题的最佳实践。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理运用设计模式可以极大地提高代码的可维护性、扩展性和复用性。本文将深入探讨策略模式(Strategy Pattern)的原理、实现方式及其在PHP中的应用。通过具体示例,我们将展示如何利用策略模式来解耦算法与对象,从而让代码更加灵活和易于管理。
24 0