首页 > 其他分享 >【软件设计模式】策略模式详解

【软件设计模式】策略模式详解

时间:2024-08-13 16:24:15浏览次数:11  
标签:策略 软件设计 void Character 模式 算法 详解 public

策略模式

策略模式是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互换。策略模式让算法的变化独立于使用算法的客户

组成

  1. 策略接口(Strategy):定义了一个所有具体策略的通用接口,各种不同的策略都遵循这个接口,它声明了一个上下文用于执行策略的方法。

    public interface Strategy {
    	public void algorithmInterface();
    }
    
  2. 具体策略(Concrete Strategy):实现策略接口的类,提供具体的策略实现

    public class ConcreteStrategy implements Strategy {
    	public void algorithmInterface() {
    		// 具体实现
    	}
    }
    
  3. 上下文(Context):持有一个策略类的引用,仅通过策略接口与该对象进行交流,最终向客户端提供具体的策略实例。

    	public class Context {
    		private Strategy strategy;
    		public void contextInterface() {
    			// 具体实现
    		}
    	}
    

其关系可由下面的UML类图表示:
策略模式示意图

适用场景

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

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

    在一个图像处理应用中,你可能有多种滤镜算法,如黑白滤镜、模糊滤镜和锐化滤镜等。使用策略模式,你可以将每种滤镜算法抽象为一个策略类,并在运行时选择要应用的滤镜算法。这样,用户可以轻松切换不同的滤镜效果,而应用程序的核心图像处理逻辑与具体的滤镜算法实现细节分离开来。

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

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

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

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

    在一个电商平台上,你可能需要实现多种优惠活动,如满减活动、折扣活动和赠品活动等。使用策略模式,你可以将每种优惠活动实现为一个策略类,并将优惠计算的逻辑委托给所选的优惠策略对象。这样,电商平台可以灵活地组合不同的优惠活动,而不需要修改核心的订单计算逻辑。

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

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

    在一个在线支付系统中,你可能需要支持多种支付方式,如信用卡支付、支付宝支付和微信支付等。使用策略模式,你可以将每种支付方式实现为一个策略类,并将支付行为委托给所选的支付策略对象。这样,系统可以根据用户选择的支付方式动态地切换支付逻辑,而不需要在代码中编写复杂的条件语句。

实现方式

  1. 从上下文类中找出修改频率较高的算法 (也可能是用于在运行时选择某个算法变体的复杂条件运算)。

  2. 声明该算法所有变体的通用策略接口。

  3. 将算法逐一抽取到各自的类中, 它们都必须实现策略接口。

  4. 在上下文类中添加一个成员变量用于保存对于策略对象的引用。 然后提供设置器以修改该成员变量。 上下文仅可通过策略接口同策略对象进行交互, 如有需要还可定义一个接口来让策略访问其数据。

  5. 客户端必须将上下文类与相应策略进行关联, 使上下文可以预期的方式完成其主要工作。

软件设计原则:开闭原则
无需对上下文进行修改就能够引入新的策略。

评价

  • 优点

    • 使用组合来代替继承

      策略模式可以避免使用继承来实现不同的行为,而是通过组合和委托来实现。这样可以减少类之间的耦合度,并且更容易扩展和修改。

    • 可以将算法的实现和使用算法的代码隔离开

    • 避免繁琐的条件运算

      使用策略模式可以避免使用大量的 if-else 或 switch-case 语句来选择不同的算法或行为。这样可以使代码更加清晰、简洁,并且易于理解和维护。

    • 可以在运行时切换对象内的算法

      策略模式允许在运行时动态地选择和切换不同的算法或行为,从而使得程序更加灵活和可扩展。不同的策略类可以提供同种行为的不同实现,客户端可以根据需要选择合适的策略。

  • 缺点

    • 客户应知晓所有策略及它们之间的不同

      策略模式要求客户端知道所有可用的策略,并且需要自行选择合适的策略。这可能会增加客户端的复杂性和理解成本。

    • 策略和环境之间的通信开销

    策略模式将算法封装在不同的策略类中,这意味着在切换不同的策略时可能会涉及到策略和上下文之间的通信开销。如果频繁切换策略,可能会导致性能下降。

    • 太多策略的类

      当系统中存在大量的策略类时,可能会导致类的数量过多,增加系统的复杂度和维护成本。因此,在设计时需要权衡策略的数量和系统的复杂度。

示例

背景:假设我们正在开发一个游戏,其中角色具有不同的职业,不同职业的角色可以选择不同的攻击策略,比如使用剑攻击、魔法攻击或者弓箭攻击。

首先,我们选择攻击算法作为我们指定的通用策略接口,不同的攻击方式,如剑攻击、魔法攻击或者弓箭攻击。

然后,我们定义一个上下文类,这里我们指定Character基类,包含攻击策略,并为不同职业创建子类。

// 策略接口
interface AttackStrategy {
    void execute();
}

// 具体策略
class SwordAttack implements AttackStrategy {
    @Override
    public void execute() {
        System.out.println("Swings a mighty sword.");
    }
}

class MagicAttack implements AttackStrategy {
    @Override
    public void execute() {
        System.out.println("Casts a powerful spell.");
    }
}

class BowAttack implements AttackStrategy {
    @Override
    public void execute() {
        System.out.println("Shoots an arrow with precision.");
    }
}

abstract class Character {
    AttackStrategy attackStrategy;

    public Character(AttackStrategy attackStrategy) {
        this.attackStrategy = attackStrategy;
    }

    public void performAttack() {
        attackStrategy.execute();
    }

    public void setAttackStrategy(AttackStrategy attackStrategy) {
        this.attackStrategy = attackStrategy;
    }
}

// 不同职业的具体实现
class Knight extends Character {
    public Knight() {
        super(new SwordAttack());
    }
}

class Mage extends Character {
    public Mage() {
        super(new MagicAttack());
    }
}

class Archer extends Character {
    public Archer() {
        super(new BowAttack());
    }
}

public class Game {
    public static void main(String[] args) {
        Character knight = new Knight();
        knight.performAttack(); // Swings a mighty sword.

        Character mage = new Mage();
        mage.performAttack(); // Casts a powerful spell.

        Character archer = new Archer();
        archer.performAttack(); // Shoots an arrow with precision.

        // 动态改变攻击策略
        knight.setAttackStrategy(new MagicAttack());
        knight.performAttack(); // Casts a powerful spell.
    }
}

通过这种方式,我们保持了Character类的灵活性和扩展性,同时也利用了策略模式来动态地改变对象的行为。每个职业类继承自Character类,并通过构造方法指定了默认的攻击策略。这样设计的好处是,我们可以很容易地添加新的职业或攻击策略,而不必修改现有的类。此外,我们也可以在运行时改变任何角色的攻击策略,从而增加了游戏的灵活性和互动性。

下图清晰地展示了策略模式在此类游戏上的应用。

在这里插入图片描述

标签:策略,软件设计,void,Character,模式,算法,详解,public
From: https://blog.csdn.net/Lewiz_124/article/details/141164161

相关文章

  • 【软件设计模式】 观察者模式详解
    观察者模式观察者模式是一种行为设计模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式特别适合于实现分布式系统中的事件处理系统,以及在需要在应用中实现广播通信时使用。组成发布者(Subject)会......
  • [全文]买椟还珠和坏事变好事?《分析模式》漫谈19
    DDD领域驱动设计批评文集做强化自测题获得“软件方法建模师”称号《软件方法》各章合集“AnalysisPatterns”的第一章有这么一句:Modelinginaprogramminglanguagealsopresentsthe danger oftyingthemodelstothatlanguage.Themodelmayusefeaturesoft......
  • 海外市场风向标:Shein全面发力半托管模式
    Shein,一个迅速崛起的全球在线时尚零售平台,以其快速的时尚反应和亲民的价格,赢得了全球消费者的青睐。自2023年起,SHEIN致力于加强其平台架构,通过提供全面的平台代运营服务、商家自我管理的运营方式和半托管模式,来满足多样化的跨境销售需求。这些模式旨在为各类跨境商家提供合适的......
  • Java注解详解:@Async异步
    使用@Async进行异步方法调用@Async是Spring框架里的一个小工具,能让你的方法在后台偷偷跑起来,不影响主线程的工作。这个方法特别适合用来处理那些不需要立即给用户反馈的任务,比如发个邮件啊,处理个大文件啥的。1.配置异步支持首先,你得在Spring配置类里开个绿灯,让......
  • [开题报告]FLASK框架涉外商务协会管理软件设计3j3jv(源码+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着全球经济一体化的深入发展,涉外商务活动日益频繁,商务协会作为促进国际交流与合作的重要平台,其管理效率与服务质量直接关系到会员企业的......
  • c语言-指针详解
    一指针变量1.1指针的概念本质上指针就是地址,我们所说的指针就是指针变量,指针变量是一个用来存放地址的指针。我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们电脑上内存是8GB/16GB/32GB等,那这些内存空......
  • 创建型模式--单例模式
    饿汉模式提前创建好了//饿汉式publicclassSingleton{privatestaticfinalSingletoninstance=newSingleton();privateSingleton(){//私有构造方法,防止外部实例化}publicstaticSingletongetInstance(){returnins......
  • C语言操作符详解
    【揭秘!】这里有你从未听过的独特见解,快来点赞关注,开启智慧之旅 目录1.操作符的分类2.二进制和进制转换2.1二进制转十进制 2.2 十进制转二进制2.3 二进制转八进制2.4 二进制转十六进制3.原码、反码、补码4.位移操作符4.1左移操作符4.2右移操作符5.位操作符......
  • `find` 命令详解
    find命令是Unix和类Unix系统(如Linux)中的一个强大工具,用于在目录树中搜索文件和目录。它提供了多种选项来进行复杂的搜索,可以根据文件的名称、类型、时间、大小等条件筛选文件。以下是find命令的详细介绍,包括常用选项和示例。基本语法find[路径][选项][测试条件][操......
  • chapter11------进入保护模式
    全局描述符表(GDT)这里要先说明下,保护模式下对内存段的访问是有限制的,简单来说就是你不能再随意的访问了,只能访问授权给你的,然后段的访问限制等等信息就记载在一个叫做全局描述表里段描述符段描述符存储了某个段的具体信息,就像我们每个人的档案一样,记录着我们的信息然后段描述......