You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

策略设计模式switch分支实例化策略时依赖过多的优化方案

策略模式嵌套依赖问题解决方案

问题场景

使用策略模式时,在上下文类的switch分支中手动实例化策略类,需要逐层手写所有嵌套依赖的实例化逻辑,代码耦合度高、维护性差,新增/修改依赖时需要改动上下文类代码,还容易引发循环依赖问题。

现有CreditService代码:

class CreditService
{
    public function addCredit($transaction)
    {
        $creditContext = new CreditContext();
        $creditStrategy = $creditContext->setStrategy($transaction->transaction_type);
        $creditStrategy->add($transaction->id);
    }
}

现有CreditContext代码,存在大量手动实例化嵌套依赖的逻辑:

class CreditContext
{
    /**
     * @param $strategy
     * @return InvoiceStrategy|UserStrategy
     * @throws \Exception
     */
    public function setStrategy($strategy)
    {
        switch ($strategy) {
            case User::class:
                return new UserStrategy(
                    new EmployerTransactionService(new TransactionService(dependencies..),dependencies..);
            case Proposal::class:
            case Milestone::class:
                return new InvoiceStrategy(
                    new TransactionService(
                        new PaymentService(new PaymentRepository(), new CreditRepository(), new TransactionRepository()),
                        new TransactionRepository(),
                        new CreditRepository(),
                        new IncomeReportService(new IncomeReportRepository()),
                        new CreditService())
                );
            default:
                throw new \Exception('not found strategy');
        }
    }
}

整洁实现方案

核心实现思路:依赖注入容器(DI)+ 策略自匹配 + 集合注入,全程无需手动传递任何嵌套依赖,同时移除硬编码switch逻辑。

1. 统一策略接口约束

定义所有策略的公共接口,增加supports方法让策略自身声明支持的交易类型,不再由上下文做硬编码映射:

interface CreditStrategyInterface
{
    public function add(int $transactionId): void;
    public function supports(string $transactionType): bool;
}

每个策略类仅需在构造函数声明自身依赖,所有依赖由DI容器自动解析注入,不需要手动实例化:

class UserStrategy implements CreditStrategyInterface
{
    // 直接声明需要的依赖,无需手动传入嵌套实例
    public function __construct(
        protected EmployerTransactionService $employerTransactionService
    ) {}

    public function supports(string $transactionType): bool
    {
        return $transactionType === User::class;
    }

    public function add(int $transactionId): void
    {
        // 具体业务逻辑
    }
}
class InvoiceStrategy implements CreditStrategyInterface
{
    // 无论依赖嵌套多少层,都只需要声明依赖本身,容器自动完成实例化
    public function __construct(
        protected TransactionService $transactionService,
        protected IncomeReportService $incomeReportService
    ) {}

    public function supports(string $transactionType): bool
    {
        return in_array($transactionType, [Proposal::class, Milestone::class]);
    }

    public function add(int $transactionId): void
    {
        // 具体业务逻辑
    }
}

2. 改造上下文类,移除switch和手动实例化逻辑

上下文类不再负责实例化策略,而是通过DI注入所有策略实例的集合,运行时遍历匹配对应策略即可:

class CreditContext
{
    /**
     * 注入所有实现了CreditStrategyInterface的策略实例
     * 所有策略的依赖都由容器提前自动解析完成,不需要手动处理
     */
    public function __construct(
        protected iterable $strategies
    ) {}

    /**
     * @throws \Exception
     */
    public function getStrategy(string $transactionType): CreditStrategyInterface
    {
        foreach ($this->strategies as $strategy) {
            if ($strategy->supports($transactionType)) {
                return $strategy;
            }
        }
        throw new \Exception('not found strategy');
    }
}

3. 改造业务服务类,通过依赖注入获取上下文

不要在业务方法中手动new上下文实例,同样通过构造函数注入,由容器管理所有实例的生命周期:

class CreditService
{
    public function __construct(
        protected CreditContext $creditContext
    ) {}

    public function addCredit($transaction)
    {
        $creditStrategy = $this->creditContext->getStrategy($transaction->transaction_type);
        $creditStrategy->add($transaction->id);
    }
}

4. 容器配置(以主流PHP框架为例)

现代PHP框架(Laravel、Symfony等)的DI容器都支持接口实例集合注入,以Laravel为例,仅需在服务提供者中添加几行绑定配置:

// 在AppServiceProvider的register方法中添加配置
// 给所有策略类打标签
$this->app->tag([UserStrategy::class, InvoiceStrategy::class], 'credit.strategies');
// 绑定CreditContext依赖,注入所有打过标签的策略实例
$this->app->bind(CreditContext::class, function ($app) {
    return new CreditContext($app->tagged('credit.strategies'));
});

方案优势

  • 零手动依赖传递:所有类的依赖不管嵌套多少层,都由DI容器自动解析注入,不需要写任何嵌套new的代码
  • 符合开闭原则:新增策略时只需要新增对应策略类、实现接口、加入标签配置即可,完全不需要修改上下文类和业务服务的代码
  • 解决循环依赖问题:所有实例由容器统一管理生命周期,单例模式复用实例,避免原代码中CreditService和InvoiceStrategy互相实例化导致的无限递归问题
  • 代码维护成本大幅降低:依赖变更时仅需修改对应类的构造函数声明,不需要逐层修改实例化逻辑

内容的提问来源于stack exchange,提问作者sina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:39:19