如何重构依赖过多的构造函数?DI新手的实际问题咨询
嘿,作为DI新手遇到这种依赖差异巨大的情况确实挺头疼的,我来给你梳理下问题和解决方案~
问题分析
你现在的Paypal类其实违反了单一职责原则——它同时承担了“创建支付”和“处理PayPal API端点”两个完全不同的职责,导致依赖变得臃肿:一个方法需要9个依赖,另一个只需要1个,不仅让类的逻辑混乱,测试起来也得mock一堆用不上的依赖,非常麻烦。
解决方案1:按职责拆分类(推荐)
最彻底的解决办法是把两个职责拆成独立的类,每个类只保留自己核心职责所需的依赖,这样依赖关系会清晰很多:
拆分后的支付创建类
class PaypalPaymentCreator { private $restAPIClient; private $db; private $logger; private $paypalGateway; private $paymentGateway; private $ordersGateway; private $usersGateway; private $resourcesGateway; private $configGateway; public function __construct( RestAPIClient $restAPIClient, Db $db, Logger $logger, PaypalGateway $paypalGateway, PaymentGateway $paymentGateway, OrdersGateway $ordersGateway, UsersGateway $usersGateway, ResourcesGateway $resourcesGateway, ConfigGateway $configGateway ) { $this->restAPIClient = $restAPIClient; $this->db = $db; $this->logger = $logger; $this->paypalGateway = $paypalGateway; $this->paymentGateway = $paymentGateway; $this->ordersGateway = $ordersGateway; $this->usersGateway = $usersGateway; $this->resourcesGateway = $resourcesGateway; $this->configGateway = $configGateway; } public function createPayment() { // 原来的createPayment逻辑,安心使用所有依赖 } }
拆分后的API端点处理类
class PaypalApiEndpointHandler { private $restAPIClient; public function __construct(RestAPIClient $restAPIClient) { $this->restAPIClient = $restAPIClient; } public function paypalApiEndpoint() { // 原来的paypalApiEndpoint逻辑,只需要这个单一依赖 } }
这样拆分后,每个类的职责明确,依赖精准:测试PaypalApiEndpointHandler时只需要mock一个RestAPIClient,而不用管其他8个依赖;后续维护时也不会因为修改一个职责的逻辑影响到另一个,完全符合SOLID原则。
解决方案2:方法注入(临时过渡方案)
如果暂时不想大动干戈拆分类,可以用方法注入的方式,把paypalApiEndpoint需要的依赖直接作为参数传入,而不通过构造函数注入:
class Paypal { // 保留原来的构造函数和所有依赖(供createPayment使用) private $restAPIClient; private $db; private $logger; private $paypalGateway; private $paymentGateway; private $ordersGateway; private $usersGateway; private $resourcesGateway; private $configGateway; public function __construct( RestAPIClient $restAPIClient, Db $db, Logger $logger, PaypalGateway $paypalGateway, PaymentGateway $paymentGateway, OrdersGateway $ordersGateway, UsersGateway $usersGateway, ResourcesGateway $resourcesGateway, ConfigGateway $configGateway ) { $this->restAPIClient = $restAPIClient; $this->db = $db; $this->logger = $logger; $this->paypalGateway = $paypalGateway; $this->paymentGateway = $paymentGateway; $this->ordersGateway = $ordersGateway; $this->usersGateway = $usersGateway; $this->resourcesGateway = $resourcesGateway; $this->configGateway = $configGateway; } public function createPayment() { // 原来的createPayment逻辑 } // 把依赖作为参数传入方法 public function paypalApiEndpoint(RestAPIClient $restAPIClient) { // 使用传入的$restAPIClient处理逻辑 } }
不过要注意,这种方式只是临时过渡手段——它并没有解决类职责混乱的根本问题,长期来看还是拆分类更利于维护。
一些DI最佳实践
- 优先遵循单一职责原则:类的职责越少,依赖越精简,DI的优势才能体现出来。
- 构造函数注入核心依赖:类的大部分方法都需要用到的依赖,用构造函数注入;单个方法特有的依赖,考虑方法注入或者拆分类。
- 避免“上帝类”:不要让一个类承担太多职责,否则会变成依赖一大堆的“上帝类”,维护和测试成本都会飙升。
内容的提问来源于stack exchange,提问作者KayakinKoder
相关产品推荐
相关产品推荐

