如何重构兼顾Strategy与Repository模式的OrderProductFactory?
OrderProductFactory重构优化方案
问题分析
原OrderProductFactory存在两个核心问题:
- 违反单一职责原则(SRP):同时负责
OrderProduct、支付策略、仓储实例三类对象的创建逻辑,职责混杂,后续新增支付方式或仓储类型时,会持续膨胀代码量,提升维护成本。 - 魔术数组
$repositoryParams不合理:依赖松散的数组传递参数,缺乏类型约束,可读性差且易出现参数名拼写错误、缺失等运行时问题。
优化方案
1. 拆分工厂,遵循单一职责
将支付策略和仓储的创建逻辑拆分到独立工厂类中,让每个工厂仅负责一类对象的创建,原OrderProductFactory仅专注于组合依赖生成OrderProduct。
拆分后的支付策略工厂
final readonly class OrderPaymentStrategyFactory { public static function create(string $type): OrderProductPaymentStrategy { return match ($type) { CardPayment::name() => new OrderCardPayment(), // 新增支付策略时,仅需扩展此处匹配分支 default => throw new InvalidArgumentException('不支持的支付策略类型: ' . $type), }; } }
拆分后的仓储工厂(解决魔术数组问题)
用强类型方法替代魔术数组,每个仓储类型对应明确的创建方法,参数类型和数量清晰可查:
final readonly class OrderRepositoryFactory { // Sqlite仓储的强类型创建方法 public static function createSqlite(string $databasePath): SqliteOrderRepository { if (empty($databasePath)) { throw new InvalidArgumentException('SqliteOrderRepository的数据库路径无效'); } return new SqliteOrderRepository($databasePath); } // 新增其他仓储类型时,添加对应强类型方法,比如: // public static function createMysql(string $host, string $dbName, string $username, string $password): MysqlOrderRepository // { // // ...逻辑实现 // } // 可选:保留统一入口方法,基于类型分发到具体创建逻辑 public static function create(string $type, mixed ...$args): OrderRepository { return match ($type) { SqliteOrderRepository::name() => self::createSqlite(...$args), // MysqlOrderRepository::name() => self::createMysql(...$args), default => throw new InvalidArgumentException('不支持的仓储类型: ' . $type), }; } }
简化后的OrderProductFactory
final readonly class OrderProductFactory { // 直接接收已实例化的依赖,职责仅为组合生成OrderProduct public static function create( OrderProductPaymentStrategy $paymentStrategy, OrderRepository $repository ): OrderProduct { return OrderProduct::for($paymentStrategy, $repository); } // 可选:保留基于类型字符串的快捷创建入口,内部调用拆分后的工厂 public static function createFromTypes( string $paymentStrategyType, string $repositoryType, mixed ...$repositoryArgs ): OrderProduct { $paymentStrategy = OrderPaymentStrategyFactory::create($paymentStrategyType); $repository = OrderRepositoryFactory::create($repositoryType, ...$repositoryArgs); return self::create($paymentStrategy, $repository); } }
2. 使用Builder模式优化创建流程
如果后续OrderProduct的依赖项增多(比如新增折扣策略、物流配置等),Builder模式会比工厂模式更灵活——它允许逐步构建对象,通过链式调用明确每个配置项,完全避免参数混乱问题。
OrderProductBuilder实现
class OrderProductBuilder { private ?OrderProductPaymentStrategy $paymentStrategy = null; private ?OrderRepository $repository = null; // 每种支付策略对应明确的配置方法 public function withCardPayment(): self { $this->paymentStrategy = new OrderCardPayment(); return $this; } // 新增支付策略时,添加对应配置方法 // public function withAlipayPayment(): self // { // $this->paymentStrategy = new OrderAlipayPayment(); // return $this; // } // 每种仓储对应明确的配置方法 public function withSqliteRepository(string $databasePath): self { $this->repository = OrderRepositoryFactory::createSqlite($databasePath); return $this; } // 新增仓储类型时,添加对应配置方法 // public function withMysqlRepository(string $host, string $dbName, string $username, string $password): self // { // $this->repository = OrderRepositoryFactory::createMysql($host, $dbName, $username, $password); // return $this; // } // 构建前校验依赖是否齐全 public function build(): OrderProduct { if ($this->paymentStrategy === null || $this->repository === null) { throw new LogicException('构建OrderProduct前必须设置支付策略和仓储'); } return OrderProduct::for($this->paymentStrategy, $this->repository); } }
使用Builder创建实例
$orderProduct = (new OrderProductBuilder()) ->withCardPayment() ->withSqliteRepository('/path/to/order.db') ->build();
优化后优势
- 职责清晰:每个工厂/Builder仅负责单一逻辑,后续扩展支付方式或仓储类型时,仅需修改对应类,不影响其他代码。
- 类型安全:强类型参数替代魔术数组,参数错误在编译阶段即可发现,减少运行时异常。
- 扩展性强:新增依赖项时,Builder模式无需修改原有方法,只需添加新的配置方法,符合开闭原则。
内容的提问来源于stack exchange,提问作者Vortex
相关产品推荐
相关产品推荐

