LARAVEL: Как использовать принцип Open Close из принципов SOLID? - PullRequest
6 голосов
/ 07 марта 2019

У меня есть следующая структура для использования Принцип Открытого Закрытия

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 и указать классу платежей использовать InvoicePaymentService в качестве реализации

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

OR

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

OR

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

Я знаю, что могу связать интерфейс с классом через поставщика услуг, но если я захочу реализовать другую реализацию оплаты, я не смогу изменить класс, верно?

Если я делаю это неправильно, пожалуйста, дайте мне знать.

1 Ответ

5 голосов
/ 07 марта 2019

Это то, что означает сервисный контейнер.Вы должны использовать контекстную привязку

Предполагая, что у вас есть интерфейс: 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 продвигает плохие принципы проектирования программного обеспечения, и довольно трудно применять принципы SOLID в laravel.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...