Когда использовать черту или услугу? - PullRequest
1 голос
/ 20 марта 2020

Для этого примера мне нужно отправить электронное письмо через некоторые AuthService, но не через другие (FacebookAuthService, GoogleAuthService и LoginFormAuthService должны отправить электронное письмо, но ApiAuthService не должно, поэтому я не могу использовать AbstractAuth родительский класс делает это).

Классы связаны здесь, так как они все об Auth, но это только пример. А как насчет несвязанных классов (один для Auth, один для Upload и т. Д.)?

С учетом этих классов:

class MailerService() { /* do stuff to send emails */}

class FacebookAuthService {
    public function connect() {}
}

class GoogleAuthService {
    public function connect() {}
}

class LoginFormAuthService {
    public function connect() {}
}

class ApiAuthService {
    public function connect() {}
}

Это более эффективно (с помощью LoginMailService):

class LoginMailService() {
    public function send(User $user, MailerService $mailer) {
        $mailer->sendTo($user->email());
        $mailer->message('Login email message');
    }
}

class FacebookAuthService {
    public function connect(User $user, LoginMailService $loginMail) {
        $loginMail->send($user->email());
    }
}

class GoogleAuthService {
    public function connect(User $user, LoginMailService $loginMail) {
        $loginMail->send($user->email());
    }
}

class LoginFormAuthService {
    public function connect(User $user, LoginMailService $loginMail) {
        $loginMail->send($user->email());
    }
}

class ApiAuthService {
    public function connect(User $user) {}
}

Или для этого (с чертами):

trait SendLoginMailTrait {
    private function sendLoginMail(User $user, MailerService $mailer) {
        $mailer->sendTo($user->email());
        $mailer->message('Login email message');
    }
}

class FacebookAuthService {
    use SendLoginMailTrait;

    public function connect(User $user) {
        $this->sendLoginMail($user->email());
    }
}

class GoogleAuthService {
    use SendLoginMailTrait;

    public function connect(User $user) {
        $this->sendLoginMail($user->email());
    }
}

class LoginFormAuthService {
    use SendLoginMailTrait;

    public function connect(User $user) {
        $this->sendLoginMail($user->email());
    }
}

class ApiAuthService {
    public function connect(User $user) {}
}

1 Ответ

3 голосов
/ 23 марта 2020

Понятия ортогональны, черты и сервисные зависимости не являются взаимозаменяемыми.

То, как вы предлагаете использовать черты в вашем вопросе, неверно, нарушает инкапсуляцию и усложняет обслуживание.

Это Ясное дело для внедрения зависимости.

Создайте интерфейс для вашего MailerService:

interface MailerServiceInterface {
    public function message($to, $body);
}
class MailerService implements MailerServiceInterface { 
    public function message($to, body) {
        /* message implementation */
    }
}

И ваши различные службы должны зависеть от этого интерфейса:

class FacebookAuthService
{
    private MailerServiceInterface $mailer;

    public __construct(MailerServiceInterface $mailer) {
        $this->mailer = $mailer;
    }
    public function connect(User $user) {
        $this->mailer->message($user->getEmail(), 'Login Message');
    }
}

Теперь код отделен, ваша «служба авторизации» зависит только от универсального c интерфейса, который может иметь несколько реализаций, и если вы создаете новую реализацию, вы можете просто «внедрить» новую реализацию, не затрагивая что-либо в нескольких классы "auth services".

Компоновка этих возможностей не только концептуально неправильна (отправка почты не является вашей обязанностью для служб auth, и эти классы не должны знать ничего о том, как эти уведомления на самом деле отправляются), но это также проблематично c практически:

В ре l Ваша служба почтовой службы также будет иметь собственную долю зависимостей (например, HTTP-клиент для связи с внешним API, доступ к некоторой конфигурации, чтобы узнать, какие учетные данные использовать при отправке сообщения и т. д. c). А с чертами вы не сможете объявить эти зависимости и не сможете удовлетворить их, не вставляя их в каждый вызов функции.

Общий вопрос о ", когда использовать черты и когда использовать службы? ", не имеет большого смысла, поскольку, как я уже говорил в начале, концепции являются ортогональными. Было бы лучше сформулировать как «, когда использовать черты? ». Ответ на этот вопрос: редко .

Но если вы хотите получить более общий ответ с действительными вариантами использования для черт, я указываю вам этот хороший пост с несколько хороших примеров.

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