LARAVEL:如何使用 SOLID 原则的开闭原则?

Posted

技术标签:

【中文标题】LARAVEL:如何使用 SOLID 原则的开闭原则?【英文标题】:LARAVEL: How to use Open Close Principle of SOLID principles? 【发布时间】:2019-03-07 09:50:06 【问题描述】:

我有以下结构使用Open Close Principle

class Payment 

    //this is not a model class
    // according to OC principle this class should not focus on the implementation

    private $paymentInterface;

    public function __construct(PaymentInterface $paymentInterface)
    
        $this->paymentInterface = $paymentInterface;
    


    //so store method does not know which implementation it will get
    public function store($request,$id)
    
        return $this->paymentInterface->store($request,$id);
    


界面

interface PaymentInterface
    public function store($request,$id = null);

包含实现的支付服务类

class PaymentService implements PaymentInterface
    public function store($request,$id = null)
        //payment store logic is here
    

控制器

class PaymentsController extends Controller

    protected $payment;

    public function __construct()
    
        $this->payment = new Payment(new PaymentService);
    

    public function storePayment(PaymentRequest $request, $id)
    
        try 
             $response = $this->payment->store($request,$id);
             return redirect()->route($this->route.'.index')->with($response['status'],$response['message']);
         catch (\Exception $e) 
            return $this->vendorDashboard($e);
        
    

我的问题是: 使用 Open-Close-Principle 是否正确? 使用上面的代码,我可以告诉控制器我可以使用 PaymentService 类来实现。

$payment = new Payment(new PaymentService);
return $payment->store($request,$id);

如果以后我想以其他方式付款,例如通过发票付款,然后我可以创建新控制器,在新类中编写新实现,例如InvoicePaymentService 并告诉 Payment 类使用 InvoicePaymentService 作为实现

$payment = new Payment(new InvoicePaymentService);
return $payment->store($request,$id);

$payment = new Payment(new PayPalPaymentService);
return $payment->store($request,$id);

$payment = new Payment(new AliPayPaymentService);
return $payment->store($request,$id);

我知道我可以通过服务提供者将接口与类绑定,但如果我想实现不同的支付实现,那么我将无法更改类,对吧?

如果我做错了,请告诉我。

【问题讨论】:

“但是如果我想实现不同的支付实现” - 你的意思是不同的支付类实现吗? 是的。我在问题中提到过。就像我想用 PayPal 或支付宝付款一样 【参考方案1】:

这就是服务容器的含义。你应该使用contextual binding

假设你有一个接口:FooInterface

你有两个具体的实现:GoodFooBadFoo

为了向控制器(或其他类)注入不同的实现你必须告诉 laravel。

$this->app->when(GoodController::class)
      ->needs(FooInterface::class)
      ->give(function () 
            return new GoodFoo();
      );


$this->app->when(BadController::class)
      ->needs(FooInterface::class)
      ->give(function () 
            return new BadFoo();
      );

控制器应该是:

class GoodController extends Controller

    protected $foo;

    public function __construct(FooInterface $foo)
    
        $this->foo = $foo;
    


class BadController extends Controller

    protected $foo;

    public function __construct(FooInterface $foo)
    
        $this->foo = $foo;
    

请注意,大多数时候 laravel 提倡糟糕的软件设计原则,而且在 laravel 中实践 SOLID 原则相当困难。

【讨论】:

太棒了。这是我在网上找到的 这意味着我们不必编写泛型类。我们可以根据不同的控制器直接将实现与接口连接起来,对吧? 视情况而定。如果您只有一个实现,并且您不打算在将来添加另一个实现,则可以不使用接口。

以上是关于LARAVEL:如何使用 SOLID 原则的开闭原则?的主要内容,如果未能解决你的问题,请参考以下文章

带构造函数的开闭原理

如何使用反射满足工厂模式中的开闭原则?

利用开闭原则 (SOLID)

开闭固原则条件失败

如何应用 SOLID 原则在 React 中整理代码之开闭原则

如何应用 SOLID 原则在 React 中整理代码之开闭原则