
本文介绍如何利用依赖注入容器重构策略模式,避免在上下文类中硬编码大量依赖实例化逻辑,提升代码可维护性与可测试性。
本文介绍如何利用依赖注入容器重构策略模式,避免在上下文类中硬编码大量依赖实例化逻辑,提升代码可维护性与可测试性。
在策略模式(Strategy Pattern)的实际应用中,一个常见痛点是:随着业务扩展,不同策略类所依赖的服务越来越多(如 TransactionService、PaymentService、CreditRepository 等),导致 CreditContext::setStrategy() 方法内充斥着冗长、重复且难以维护的构造函数调用链——这不仅违反了单一职责原则,也使单元测试变得困难,更阻碍了策略的灵活替换与扩展。
理想的解决方案不是手动 new 实例,而是交由依赖注入容器(DI Container)统一管理对象生命周期与依赖解析。以 PHP 社区广泛采用的 PHP-DI 或 League/Container 为例,我们可将各类策略类及其依赖声明为容器中的服务,并通过类型自动解析,彻底消除硬编码依赖。
以下是重构后的关键步骤与示例:
✅ 第一步:注册策略服务到容器
在应用启动时(如 bootstrap.php 或服务提供者中),向容器注册各策略类及其依赖:
$container = new Container();
$container->add(TransactionService::class)
->withArguments([
new PaymentService(
$container->get(PaymentRepository::class),
$container->get(CreditRepository::class),
$container->get(TransactionRepository::class)
),
$container->get(TransactionRepository::class),
$container->get(CreditRepository::class),
$container->get(IncomeReportService::class),
$container->get(CreditService::class)
]);
$container->add(UserStrategy::class)
->withArguments([new EmployerTransactionService($container->get(TransactionService::class))]);
$container->add(InvoiceStrategy::class)
->withArguments([$container->get(TransactionService::class)]);
// 绑定接口或类名作为标识符(推荐使用 FQCN)
$container->add(User::class, UserStrategy::class);
$container->add(Proposal::class, InvoiceStrategy::class);
$container->add(Milestone::class, InvoiceStrategy::class);✅ 第二步:精简 Context 类,专注策略分发
CreditContext 不再负责创建对象,只做策略路由与类型校验:
class CreditContext
{
private ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function setStrategy(string $strategyType): CreditStrategyInterface
{
if (!$this->container->has($strategyType)) {
throw new RuntimeException("Strategy for '{$strategyType}' not registered");
}
return $this->container->get($strategyType);
}
}✅ 第三步:更新业务服务,注入 Context
CreditService 改为依赖注入 CreditContext,确保其本身也由容器管理:
class CreditService
{
private CreditContext $creditContext;
public function __construct(CreditContext $creditContext)
{
$this->creditContext = $creditContext;
}
public function addCredit(Transaction $transaction): void
{
$strategy = $this->creditContext->setStrategy($transaction->transaction_type);
$strategy->add($transaction->id);
}
}? 注意事项与最佳实践:
- ✅ 所有策略类应实现统一接口(如 CreditStrategyInterface),保证 setStrategy() 返回类型安全;
- ✅ 避免在容器中直接 new 依赖对象,优先使用 withArguments() 或 add() 的闭包方式延迟解析;
- ✅ 将策略映射关系(如 User::class → UserStrategy::class)集中配置,便于审计与扩展;
- ❌ 切勿在 switch 中重复 new 多层嵌套依赖——这是反模式信号,应立即重构;
- ? 后续新增策略(如 Refund::class)只需注册服务 + 添加映射,无需修改 CreditContext 逻辑。
通过 DI 容器驱动的策略模式,你获得的不仅是更干净的代码,更是松耦合、易测试、可插拔的架构能力——这才是面向对象设计的真正价值所在。

















