策略模式(Strategy Pattern)工程规范与实现(Go / Rust 双语言)

策略模式(Strategy Pattern)工程规范与实现(Go / Rust 双语言)

1 概述

1.1 定义

策略模式属于行为型设计模式,定义一系列可互换的算法(策略),将每一种算法独立封装,使算法的变化与使用者解耦。
核心思想:封装变化、算法可替换、运行时动态切换。

工程角色(精简版):

  • Strategy(策略接口):统一算法行为规范
  • ConcreteStrategy(具体策略):不同实现算法逻辑

1.2 适用场景

推荐使用

  1. 同一业务存在多种分支算法,且需要动态切换(加密、校验、排序、计费、日志格式);
  2. 大量if/else、switch 分支臃肿,需要消除分支嵌套;
  3. 算法逻辑频繁迭代新增,希望新增策略不改动上下文代码(开闭原则);
  4. 需要统一管控多种算法生命周期、统一入参出参规范。

避免滥用

  1. 算法固定、几乎无变更、无需切换;
  2. 仅少量分支,过度拆分导致类/结构体爆炸、增加维护成本。

1.3 解决核心痛点

  1. 消灭业务层冗长 if/else、分支嵌套;
  2. 算法逻辑独立隔离,单一职责,便于单元测试;
  3. 支持运行时动态替换策略,灵活适配不同场景;
  4. 新增算法无需修改上层逻辑,符合开闭原则。
    核心原则:变的是算法,不变的是调用方式。

2 通用编码规范

  1. 定义统一策略接口,约束所有算法入参、出参、行为;
  2. 每一种算法独立实现一个策略类/结构体,禁止策略内部混杂多种分支;
  3. 通过 Context 上下文 统一调度,业务层只依赖上下文,不依赖具体策略;
  4. 支持运行时动态替换策略实例;
  5. 策略无状态优先,保证可复用、线程安全;
  6. 策略枚举映射统一收口,集中注册、方便遍历与兜底。

3 Go 标准实现

Go 采用 接口 + 多结构体实现 + Context 上下文 标准工程写法,彻底消除 if-else。

3.1 完整代码实现

package main

import "fmt"

// ====================== 策略接口 ======================
// SortStrategy 统一排序策略接口,规范算法行为
type SortStrategy interface {
	Sort([]int) []int
}

// ====================== 具体策略实现 ======================
// AscSort 升序排序策略(无状态、可全局复用)
type AscSort struct{}

// Sort 实现升序排序逻辑
func (a *AscSort) Sort(arr []int) []int {
	res := make([]int, len(arr))
	copy(res, arr)
	for i := 0; i < len(res); i++ {
		for j := i + 1; j < len(res); j++ {
			if res[i] > res[j] {
				res[i], res[j] = res[j], res[i]
			}
		}
	}
	return res
}

// DescSort 降序排序策略(无状态、可全局复用)
type DescSort struct{}

// Sort 实现降序排序逻辑
func (d *DescSort) Sort(arr []int) []int {
	res := make([]int, len(arr))
	copy(res, arr)
	for i := 0; i < len(res); i++ {
		for j := i + 1; j < len(res); j++ {
			if res[i] < res[j] {
				res[i], res[j] = res[j], res[i]
			}
		}
	}
	return res
}

// ====================== 上下文 Context ======================
// SortContext 策略调度上下文,统一入口、动态切换策略
type SortContext struct {
	strategy SortStrategy
}

// NewSortContext 初始化调度上下文
func NewSortContext() *SortContext {
	return &SortContext{}
}

// SetStrategy 运行时动态替换排序策略
func (c *SortContext) SetStrategy(s SortStrategy) {
	c.strategy = s
}

// Execute 统一执行算法,兜底空策略,避免空指针panic
func (c *SortContext) Execute(arr []int) []int {
	if c.strategy == nil {
		return arr
	}
	return c.strategy.Sort(arr)
}

func main() {
	// 测试数据
	data := []int{3, 1, 4, 2, 5}
	ctx := NewSortContext()

	// 切换升序策略执行
	ctx.SetStrategy(&AscSort{})
	fmt.Println("升序排序结果:", ctx.Execute(data))

	// 动态切换降序策略执行
	ctx.SetStrategy(&DescSort{})
	fmt.Println("降序排序结果:", ctx.Execute(data))
}

3.2 Go 专项约束

  1. 策略结构体尽量无状态,全局可复用,减少内存分配;
  2. 禁止在单个策略实现内写多分支逻辑;
  3. 业务层只依赖 Context,不直接依赖具体策略结构体;
  4. 可配合 map 实现策略注册器,统一路由分发。

3.3 工程进阶:策略注册器(完整版、无分支路由)

通过注册器统一收口所有策略,基于枚举/标识自动路由,业务层零 if/else,支持动态注册、兜底容错,适配企业级多策略迭代场景。

package main

import (
	"fmt"
	"sync"
)

// ====================== 策略枚举标识 ======================
type SortType string

const (
	SortAsc  SortType = "asc"
	SortDesc SortType = "desc"
)

// ====================== 策略接口 ======================
type SortStrategy interface {
	Sort([]int) []int
}

// ====================== 具体策略 ======================
type AscSort struct{}

func (a *AscSort) Sort(arr []int) []int {
	res := make([]int, len(arr))
	copy(res, arr)
	for i := 0; i < len(res); i++ {
		for j := i + 1; j < len(res); j++ {
			if res[i] > res[j] {
				res[i], res[j] = res[j], res[i]
			}
		}
	}
	return res
}

type DescSort struct{}

func (d *DescSort) Sort(arr []int) []int {
	res := make([]int, len(arr))
	copy(res, arr)
	for i := 0; i < len(res); i++ {
		for j := i + 1; j < len(res); j++ {
			if res[i] < res[j] {
				res[i], res[j] = res[j], res[i]
			}
		}
	}
	return res
}

// ====================== 策略注册器(核心) ======================
var (
	strategyRegister = make(map[SortType]SortStrategy)
	registerMu       sync.RWMutex
)

// RegisterStrategy 注册策略
func RegisterStrategy(t SortType, s SortStrategy) {
	registerMu.Lock()
	defer registerMu.Unlock()
	strategyRegister[t] = s
}

// GetStrategy 获取策略(带兜底)
func GetStrategy(t SortType) SortStrategy {
	registerMu.RLock()
	defer registerMu.RUnlock()
	// 默认升序兜底
	if s, ok := strategyRegister[t]; ok {
		return s
	}
	return &AscSort{}
}

// ====================== 上下文 ======================
type SortContext struct {
	strategy SortStrategy
}

func NewSortContext() *SortContext {
	return &SortContext{}
}

func (c *SortContext) SetStrategy(s SortStrategy) {
	c.strategy = s
}

func (c *SortContext) Execute(arr []int) []int {
	if c.strategy == nil {
		return arr
	}
	return c.strategy.Sort(arr)
}

// ====================== 初始化注册 ======================
func init() {
	RegisterStrategy(SortAsc, &AscSort{})
	RegisterStrategy(SortDesc, &DescSort{})
}

func main() {
	data := []int{3, 1, 4, 2, 5}
	ctx := NewSortContext()

	// 基于标识自动路由,无任何分支
	ctx.SetStrategy(GetStrategy(SortAsc))
	fmt.Println("注册器-升序:", ctx.Execute(data))

	ctx.SetStrategy(GetStrategy(SortDesc))
	fmt.Println("注册器-降序:", ctx.Execute(data))

	// 非法类型自动兜底
	ctx.SetStrategy(GetStrategy("unknown"))
	fmt.Println("非法策略-兜底升序:", ctx.Execute(data))
}

Go 注册器核心优势

  1. 新增策略只需实现接口+注册,无需修改路由逻辑,完全符合开闭原则;
  2. 读写锁保障并发安全,支持运行时动态注册策略;
  3. 天然兜底机制,避免策略不存在导致业务异常;
  4. 彻底消灭业务层分支判断,路由逻辑统一收口。

4 Rust 标准实现

Rust 工程标准方案:Trait 策略接口 + 多实现结构体 + Context 上下文,零开销抽象、安全可控。

4.1 完整代码实现

// ====================== 策略 Trait ======================
pub trait SortStrategy {
    fn sort(&self, arr: &[i32]) -> Vec<i32>;
}

// ====================== 具体策略 ======================
/// 升序策略
#[derive(Default)]
pub struct AscSort;

impl SortStrategy for AscSort {
    fn sort(&self, arr: &[i32]) -> Vec<i32> {
        let mut res = arr.to_vec();
        res.sort();
        res
    }
}

/// 降序策略
#[derive(Default)]
pub struct DescSort;

impl SortStrategy for DescSort {
    fn sort(&self, arr: &[i32]) -> Vec<i32> {
        let mut res = arr.to_vec();
        res.sort_by(|a, b| b.cmp(a));
        res
    }
}

// ====================== 上下文 Context ======================
pub struct SortContext {
    strategy: Option<Box<dyn SortStrategy>>,
}

impl SortContext {
    pub fn new() -> Self {
        Self { strategy: None }
    }

    // 动态设置策略
    pub fn set_strategy(&mut self, s: Box<dyn SortStrategy>) {
        self.strategy = Some(s);
    }

    // 统一执行入口
    pub fn execute(&self, arr: &[i32]) -> Vec<i32> {
        self.strategy.as_ref().map(|s| s.sort(arr)).unwrap_or(arr.to_vec())
    }
}

fn main() {
    let data = [3, 1, 4, 2];
    let mut ctx = SortContext::new();

    ctx.set_strategy(Box::new(AscSort::default()));
    println!("升序:{:?}", ctx.execute(&data));

    ctx.set_strategy(Box::new(DescSort::default()));
    println!("降序:{:?}", ctx.execute(&data));
}

4.2 工程进阶:策略注册器(完整版、静态映射+容错路由)

Rust 基于枚举+静态注册实现零开销策略路由,无动态哈希表开销,编译期校验合法策略,运行时兜底容错,适配高性能工程场景。

use std::collections::HashMap;
use std::sync::OnceLock;

// ====================== 策略枚举标识 ======================
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SortType {
    Asc,
    Desc,
}

// ====================== 策略 Trait 接口 ======================
pub trait SortStrategy {
    fn sort(&self, arr: &[i32]) -> Vec<i32>;
}

// ====================== 具体策略实现 ======================
#[derive(Debug, Default)]
pub struct AscSort;
impl SortStrategy for AscSort {
    fn sort(&self, arr: &[i32]) -> Vec<i32> {
        let mut res = arr.to_vec();
        res.sort_unstable();
        res
    }
}

#[derive(Debug, Default)]
pub struct DescSort;
impl SortStrategy for DescSort {
    fn sort(&self, arr: &[i32]) -> Vec<i32> {
        let mut res = arr.to_vec();
        res.sort_unstable_by(|a, b| b.cmp(a));
        res
    }
}

// ====================== 策略注册器(静态全局) ======================
static STRATEGY_REGISTER: OnceLock<HashMap<SortType, Box<dyn SortStrategy + Send + Sync>>> = OnceLock::new();

/// 初始化所有策略(程序启动一次性注册)
fn init_strategy_register() -> HashMap<SortType, Box<dyn SortStrategy + Send + Sync>> {
    let mut map = HashMap::<SortType, Box<dyn SortStrategy + Send + Sync>>::new();
    map.insert(SortType::Asc, Box::new(AscSort::default()));
    map.insert(SortType::Desc, Box::new(DescSort::default()));
    map
}

/// 根据类型获取策略,默认升序兜底
pub fn get_strategy(typ: SortType) -> &'static Box<dyn SortStrategy + Send + Sync> {
    let register = STRATEGY_REGISTER.get_or_init(init_strategy_register);
    register.get(&typ).unwrap_or_else(|| register.get(&SortType::Asc).unwrap())
}

// ====================== 上下文 ======================
pub struct SortContext {
    strategy: Option<&'static Box<dyn SortStrategy + Send + Sync>>,
}

impl SortContext {
    pub fn new() -> Self {
        Self { strategy: None }
    }

    pub fn set_strategy(&mut self, s: &'static Box<dyn SortStrategy + Send + Sync>) {
        self.strategy = Some(s);
    }

    pub fn execute(&self, arr: &[i32]) -> Vec<i32> {
        self.strategy.as_ref().map(|s| s.sort(arr)).unwrap_or_else(|| arr.to_vec())
    }
}

fn main() {
    let data = [3, 1, 4, 2, 5];
    let mut ctx = SortContext::new();

    // 枚举路由,零分支
    ctx.set_strategy(get_strategy(SortType::Asc));
    println!("注册器-升序:{:?}", ctx.execute(&data));

    ctx.set_strategy(get_strategy(SortType::Desc));
    println!("注册器-降序:{:?}", ctx.execute(&data));
}

Rust 注册器核心优势

  1. 基于 OnceLock 静态一次性初始化,零重复开销、线程安全;
  2. 枚举管控策略类型,编译期拦截非法策略标识,减少运行时异常;
  3. 绑定 Send + Sync,支持全局多线程共享策略实例;
  4. 静态引用复用实例,无频繁堆分配,性能优于动态注册方案。

4.3 Rust 进阶:泛型静态分发(零开销、编译期绑定)

前文 Box 为动态分发,运行时查表存在微小开销;
泛型静态分发通过编译器单态化实现编译期策略绑定,无虚表、无运行时开销,是 Rust 策略模式最高性能方案,适合策略固定、无需运行时动态切换的高性能场景。

// ====================== 策略 Trait(静态分发专用) ======================
pub trait SortStrategy {
    fn sort(&self, arr: &[i32]) -> Vec<i32>;
}

// ====================== 具体策略实现 ======================
#[derive(Debug, Default)]
pub struct AscSort;
impl SortStrategy for AscSort {
    fn sort(&self, arr: &[i32]) -> Vec<i32> {
        let mut res = arr.to_vec();
        res.sort_unstable();
        res
    }
}

#[derive(Debug, Default)]
pub struct DescSort;
impl SortStrategy for DescSort {
    fn sort(&self, arr: &[i32]) -> Vec<i32> {
        let mut res = arr.to_vec();
        res.sort_unstable_by(|a, b| b.cmp(a));
        res
    }
}

// ====================== 泛型上下文(静态分发核心) ======================
/// 泛型约束:编译期绑定具体策略类型,零开销抽象
pub struct SortContext<S: SortStrategy> {
    strategy: S,
}

impl<S: SortStrategy> SortContext<S> {
    // 构造方法:传入任意实现策略 trait 的实例
    pub fn new(strategy: S) -> Self {
        Self { strategy }
    }

    // 统一执行入口,编译期确定具体实现
    pub fn execute(&self, arr: &[i32]) -> Vec<i32> {
        self.strategy.sort(arr)
    }
}

fn main() {
    let data = [3, 1, 4, 2, 5];

    // 编译期绑定升序策略
    let asc_ctx = SortContext::new(AscSort::default());
    println!("静态分发-升序:{:?}", asc_ctx.execute(&data));

    // 编译期绑定降序策略
    let desc_ctx = SortContext::new(DescSort::default());
    println!("静态分发-降序:{:?}", desc_ctx.execute(&data));
}

4.4 静态分发专项规范

  1. 泛型上下文必须约束 S: SortStrategy,保证编译期类型安全;
  2. 策略优先无状态设计,可直接通过 Default 构造,零内存分配;
  3. 追求极致性能场景优先静态分发,业务动态灵活场景选用动态分发;
  4. 静态分发无法配合运行时注册器,仅适用于编译期已知的固定策略集合。

4.5 Rust 专项约束

  1. 使用 dyn Trait 特征对象实现动态分发,支持运行时策略切换;
  2. 策略结构体设计为无状态静态常量,全局零拷贝复用,性能最优;
  3. Trait 约束 Send + Sync,天然支持多线程并发安全;
  4. 接口保持单一职责,仅定义核心算法行为,杜绝冗余方法;
  5. 统一静态注册方案,彻底修复特征对象类型不匹配编译错误;

4.6 静态分发 vs 动态分发 核心差异

对比维度 静态分发(泛型) 动态分发(dyn Trait)
绑定时机 编译期确定具体策略类型 运行时动态匹配策略实现
运行时开销 零开销、无虚表跳转 存在虚表查表微小开销
策略切换 不支持运行时动态切换 支持运行时随时替换策略
二进制体积 略大(单态化生成多份代码) 更小(共用一套分发逻辑)
适用场景 高性能、策略固定、无需动态切换 业务灵活、需动态路由、适配注册器

5 Go / Rust 策略模式核心对比

对比维度 Go Rust
抽象能力 Interface 隐式实现 Trait 显式实现
多态方式 接口指针动态多态 dyn Trait 特征对象多态
策略切换 运行时可动态替换 运行时可动态替换
性能开销 极低 零开销抽象
编译约束 无编译期强制校验 编译期严格校验实现
注册机制 RWMutex+Map 动态注册 OnceLock 静态一次性注册
适用场景 快速迭代、动态扩展策略 高性能、高可靠、强规范项目

6 最佳实践与常见误区

6.1 常见误区

  1. 策略内部继续写大量 if/else,没有真正解耦分支;
  2. 过度拆分策略,简单逻辑强行拆类,造成代码碎片化;
  3. 上下文混入业务逻辑,违背「调度与实现分离」;
  4. 策略带大量可变状态,引发并发数据竞争;
  5. 业务层直接调用具体策略,绕过上下文统一管控。

6.2 最佳实践

  1. 分支多、迭代频繁必用策略模式,彻底消灭臃肿判断;
  2. 所有具体策略单一职责、互相独立,新增策略无需改旧代码;
  3. 上下文仅负责策略持有、切换、调度,不实现具体算法;
  4. 策略设计为无状态,全局复用,提升性能、减少内存分配;
  5. 可扩展策略注册器,通过枚举/字符串自动路由策略,进一步简化业务层。
posted @ 2026-07-17 17:19  等你下课啊  阅读(4)  评论(0)    收藏  举报