何时使用特质或服务?

问题描述 投票:1回答:2

对于此示例,我需要通过某些AuthService发送电子邮件,但不需要通过其他电子邮件发送(FacebookAuthServiceGoogleAuthServiceLoginFormAuthService应该发送电子邮件,但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) {}
}
php oop service traits
2个回答
0
投票
您提出的在问题中使用特征的方法是错误的,破坏了封装并使得维护更加困难。

这是依赖项注入的明显情况。

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

现在代码已解耦,您的“身份验证服务”仅取决于可以具有多个实现的通用接口,如果您创建新的实现,则可以简单地“注入”新的实现,而无需触及多个“身份验证服务”类。

组合这些功能不仅在概念上是错误的(发送邮件实际上不是您的身份验证服务责任,而且这些类对这些通知的实际发送方式一无所知),但实际上也存在问题:

在现实生活中,您的邮件服务也将拥有自己的依赖关系(例如,与外部API进行通信的HTTP客户端,访问某些配置以了解在发送消息时使用哪些凭据等)。使用特征,您将无法声明这些依赖关系,也无法在不将其注入每个函数调用的情况下满足它们。

关于“

何时使用特征以及何时使用服务?的一般问题”没有多大意义,因为正如我一开始所说的那样,概念是正交的。最好将其表述为“

何时使用特征?”。答案是:很少

但是,如果您想使用有关特征的有效用例的更一般的答案,我会通过一些好的示例将您指向this good post

-1
投票
“ IS A”或

“ HAS A”。]]例如,FacebookAuthService是A AuthServiceAuthService具有名为MailerService的服务或您需要设计的任何其他结构。

所以,如果一个类需要继承多种行为怎么办?

traits

用PHP解决了这个问题,在Java中,我们有

interface的默认方法

。但最好还是将特征用于相同类型的相同行为。否则,您可能会认为它是实用程序,并定义了一个[[HAS A关系。特质可以具有可在多个类中使用的方法和抽象方法。在设计中可能需要编写抽象方法和类。这取决于项目的规模和软件体系结构的最佳实践。我强烈建议您学习《 [[四种设计模式的使用]]》,您还可以发现this link确实有用。那么当您面对封装和多态性概念时,您会感到很高兴编写空方法。编写清晰的代码是在长期支持下的大型项目中的一个问题。这个概念超出了单元的最佳效率,您可能会为开发付出更多的代价,而在维护和扩展上的花费会更少。
© www.soinside.com 2019 - 2024. All rights reserved.