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

Afr*_*mad 6 php open-closed-principle solid-principles laravel

我有以下结构可以使用开闭原理

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

接口

interface PaymentInterface{
    public function store($request,$id = null);
}
Run Code Online (Sandbox Code Playgroud)

包含实现的支付服务类

class PaymentService implements PaymentInterface{
    public function store($request,$id = null){
        //payment store logic is here
    }
}
Run Code Online (Sandbox Code Playgroud)

控制者

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

$payment = new Payment(new PaymentService);
return $payment->store($request,$id);
Run Code Online (Sandbox Code Playgroud)

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

$payment = new Payment(new InvoicePaymentService);
return $payment->store($request,$id);
Run Code Online (Sandbox Code Playgroud)

要么

$payment = new Payment(new PayPalPaymentService);
return $payment->store($request,$id);
Run Code Online (Sandbox Code Playgroud)

要么

$payment = new Payment(new AliPayPaymentService);
return $payment->store($request,$id);
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过服务提供商将Interface绑定到类,但是如果我想实现其他支付方式,那么我将无法更改类,对吗?

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

Yar*_*dam 5

这就是服务容器的代表。您应该使用上下文绑定

假设您有一个接口: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();
      });
Run Code Online (Sandbox Code Playgroud)

控制器应该是:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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