Допустим, у вас есть метод в черте, который требует модель Cat
и модель Dog
.Каждый раз, когда вы используете эту черту, вам нужно передать экземпляр Cat
и экземпляр Dog
, чтобы он выполнял свою работу.
В конце концов это утомителен.И что произойдет, если вы в конечном итоге добавите особенность, а для этой черты теперь требуется модель Bird
?Теперь у вас есть много кода, который нужно изменить, чтобы начать передавать Bird
методу в признаке каждый раз, когда вы захотите его использовать.
Здесь класс обслуживания становится очень удобным.В конструкторе класса обслуживания вы можете вставить модель User
, Permission
и Role
следующим образом ...
public function __construct(Cat $cat, Dog $dog, Bird $bird)
{
$this->cat = $cat;
$this->dog = $dog;
$this->bird = $bird;
}
Затем вы можете добавить в свое приложение поставщика услуг, который инструктируетLaravel, как создать этот класс обслуживания, передав соответствующие модели.Оттуда вы можете автоматически внедрить эту услугу в ваши контроллеры, если считаете нужным, где в данный момент вы просто используете для этого черту.
Это означает, что если вам когда-либо понадобилось добавить зависимость, вам нужно толькообновить один, возможно два файла.Сам класс обслуживания для добавления дополнительных элементов в конструктор и, возможно, поставщика услуг.Все контроллеры, которые используют это, не должны обновляться для передачи этих дополнительных элементов конструктору, поскольку он обрабатывается Laravel (более подходящим образом - контейнер IoC).
Это также чрезвычайно полезно для тестирования.При внедрении зависимостей в класс проще просто настроить среду тестирования для имитации этих зависимостей, чем пытаться создавать насмешки на лету для передачи в методы trait.Также сложнее протестировать черту, поскольку что-то нужно use
для этой черты, чтобы протестировать методы черты.
// we can use a service provider to tell laravel how to create this service (https://laravel.com/docs/5.7/providers)
class PetService
{
protected $cat;
protected $dog;
protected $bird;
public function __construct(Cat $cat, Dog $dog, Bird $bird)
{
$this->cat = $cat;
$this->dog = $dog;
$this->bird = $bird;
}
public function doStuff()
{
// does things with $this->cat, $this->dog, $this->bird
}
}
class PetController
{
// use PetTrait;
protected $petService;
// laravel will automatically create the PetService for us and pass it into the constructor when building this controller (https://laravel.com/docs/5.7/container)
public function __construct(PetService $petService)
{
$this->petService = $petService;
}
public function someControllerMethod()
{
// $this->doStuff(new Cat, new Dog, new Bird); // In order to modify this method, we need to update each time it's used.
$this->petService->doStuff(); // We don't need to worry about passing in arguments since it's handled by the service container when constructing the pet service and can make changes without updating each controller that uses it.
}
}
И чтобы перейти к деталям, что произойдет, если вы решите Bird
теперь для правильной работы требуется экземпляр Chicken
, Turkey
, Dodo
.Теперь вам нужно снова пройтись по всем признакам, использующим Bird
, и обновить каждый из них, чтобы передать экземпляр каждой из его зависимостей.
Вот почему выгодно использовать контейнер услуг и поставщиков для планирования ипостроить ваши зависимости ваших классов обслуживания.Это значительно повышает удобство сопровождения вашего приложения.Это было бы наиболее полезным в очень большом и сложном приложении.
Однако, если ваше приложение довольно простое, оно может быть не таким полезным и, возможно, даже добавить ненужную сложность, и черты могут фактически быть лучше использовать в этой точке, если они имеют больше смысла для вас.Нехорошо, чтобы ваше приложение было гибким при использовании сервисов, когда это не нужно.