LARAVEL: 如何使用SOLID原则的Open Close Principle?
LARAVEL: How to use Open Close Principle of SOLID principles?
我有以下结构可以使用开闭原则
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包含实现
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 class 来实现。
$payment = new Payment(new PaymentService);
return $payment->store($request,$id);
如果以后我想以不同的方式付款,例如通过发票付款然后我可以创建新的控制器,在新的 class 中编写新的实现,例如InvoicePaymentService 并告诉 Payment class 使用 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);
我知道我可以通过服务提供商将接口与 class 绑定,但是如果我想实现不同的支付实现,那么我将无法更改 class,对吧?
如果我做错了,请告诉我。
这就是服务容器的含义。你应该使用 contextual binding
假设你有一个接口:FooInterface
你有两个具体的实现:GoodFoo 和 BadFoo
为了向控制器(或其他 类)注入不同的实现 你必须告诉它 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 原则。
我有以下结构可以使用开闭原则
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包含实现
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 class 来实现。
$payment = new Payment(new PaymentService);
return $payment->store($request,$id);
如果以后我想以不同的方式付款,例如通过发票付款然后我可以创建新的控制器,在新的 class 中编写新的实现,例如InvoicePaymentService 并告诉 Payment class 使用 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);
我知道我可以通过服务提供商将接口与 class 绑定,但是如果我想实现不同的支付实现,那么我将无法更改 class,对吧?
如果我做错了,请告诉我。
这就是服务容器的含义。你应该使用 contextual binding
假设你有一个接口:FooInterface
你有两个具体的实现:GoodFoo 和 BadFoo
为了向控制器(或其他 类)注入不同的实现 你必须告诉它 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 原则。