使用存储库模式的Laravel SOLID

时间:2017-10-03 12:44:54

标签: php laravel

我希望(此时此外)可以遵循SOLID原则,但我的思绪将会爆发。

我在Laravel中阅读了很多关于存储库模式的帖子,以遵循SOLID原则。我的问题与this question非常相似。但我不明白我怎么能不违反工厂模式

中的开放/封闭校长

我正在开发一个双因素身份验证系统,我有多种方法可以用作tfa。

现在:

  • Authenticator App
  • SMS

让我们跳转到代码:

控制器:(无工厂)

public function index(Request $request)
{   
    // Violate the OCP. I'm modyfing the class.
    switch ($request->method) {
        case 'authenticator':
            $tfaMethod = new Authenticator;
            break;
        case 'sms':
            $tfaMethod = new SMS;
            break;
    }

    return (new TwoFactorMethod)->process($this->currentUser, $tfaMethod);
}

TwoFactorMethod类:

public function process($user, MethodInterface $method)
{
    return $method->process($user);
}

每个方法都有自己的类。没关系。但是,如果我想添加一个新方法,例如:电子邮件,我将使用switch case打破班级中的OCP。

我怎样才能修复"?或者只是我身边的误会?

谢谢!

2 个答案:

答案 0 :(得分:5)

您可以使用TfaMethodRegisty,也许是这样的:

class TfaMethodRegistry
{
    protected $methods = [];


    public function register($name, $class)
    {
        $this->methods[$name] = $class;
    }


    public function get($name)
    {
        return $this->methods[$name];
    }
}

然后在AppServiceProvider中填充它:

public function register()
{
    $this->app->bind('App\TfaMethodRegistry', function ($app) {
        $registry new TfaMethodRegistry;

        $registry->register('sms', new Sms);
        $registry->register('authenticator', new Authenticator);

        return $registry;
    });
}

然后您可以让Laravel IoC-Container注入您的控制器或任何您需要的地方:

public function index(Request $request, TfaMethodRegistry $registry)
{   
    $tfaMethod = $registry->get($request->method);

    return (new TwoFactorMethod)->process($this->currentUser, $tfaMethod);
}

所以基本上你将可用的方法视为配置,但也可以在运行时添加更多,而无需编辑任何内容。

只是一个小小的提示:不要对此过于疯狂,也不要过于虔诚地使用整个SOLID。通常情况下,KISS比SOLID更好:)

答案 1 :(得分:1)

除非您正在编写一个供其他客户使用的库,否则我建议您让工厂具备这方面的知识,特别是如果它构造的类列表相当短且是静态的。您将获得主要的好处:不必使用switch / case语句和集中式知识来谜题化其余代码,但不会有太多麻烦。

这看起来如何:

class TwoFactorAuthenticatorFactory {
    public static function createFromMethod(string $method): TwoFactorAuthenticator
    {
        switch ($method) {
            case 'authenticator':
                return new Authenticator();
            case 'sms':
                return new SMS();
        }

        throw new RuntimeException(sprintf('Method %s could not be resolved to an authenticator.', $method));
    }
}

用法:

TwoFactorAuthenticatorFactory::createFromMethod($request->method);

我打算快速告诉你如何解决这个问题"教条和#34;但是@Quasdunk用一个很好的答案击败了我:)请注意,除了制作东西(可能不必要地)更抽象,该解决方案在如何将知识从域移动到框架基础结构层方面也存在很大的缺陷。这将把你绑定到框架,这是你通常想要避免的。