AppServiceProvider中基于模型解析服务

Resolving service based on model in AppServiceProvider

给你一个简短的看法:我正在尝试根据条件进行重定向。如果请求满足给定目的地的条件,您将重定向到特定目的地。

我有 Destination 模型,它有很多条件(条件模型)。我有许多扩展基本条件模型的条件,如 DateConditionLocationCondition 等(由多态关系构成)。每个条件类型都应该有 'service' 来告诉给定的条件是否匹配请求。示例 DateCondition 应该有自己的 DateConditionMatcher 实现 ConditionMatcherInterface.
(只是 public function match($condition, $request))。

我想用 SOLID 的 Open Closed 原则来写它。首先,我想直接向条件模型添加 getMatcher() 函数,并为每种条件类型添加 return 不同的 ConditionMatcher,但是一些 ConditionMatchers 需要在构造函数中传递一些其他服务,所以它会迫使我也将它们注入 Condition 模型中,这是不好的做法。

也许在 ServiceProvider 中使用上下文绑定可以解决这个问题,但如何解决? 我不知道如何将模型耦合到正确的 ConditionMatcher,然后像这样自由使用它:

foreach ($destination->conditions as $condition){
       $isMatched = $this->conditionMatcher->match($condition, $request);
}

在 $this->conditionMatcher 下总是有正确的 ConditionMatcher。 我希望有人理解我不太清楚的信息。

我一夜之间就有了一个想法,做一个能保留所有匹配器的服务。该解决方案的唯一缺点是注入每个匹配器。

class ConditionResolver implements ConditionResolverInterface
{
    /** @var ConditionMatcherInterface[] */
    private $conditionMatchers = [];

    public function __construct(
       DateConditionMatcher $dateConditionMatcher, 
       TimeConditionMatcher $timeConditionMatcher,
       LocationConditionMatcher $locationConditionMatcher
    ) {
       $this->conditionMatchers[DateCondition::class] = $dateConditionMatcher;
       $this->conditionMatchers[TimeCondition::class] = $timeConditionMatcher;
       $this->conditionMatchers[LocationCondition::class] = $locationConditionMatcher;
    }
}

所以现在我可以使用正确的匹配器以这种方式给定条件(简化):

foreach ($model->conditions as $condition)
{
    $this->conditionMatchers[get_class($condition)]->match($condition, $request);
}

它允许我将各种服务注入 AppServiceProvider 中的匹配器。

$this->app->singleton(LocationServiceInterface::class, function($app){
   return new LocationService();
});

$this->app->singleton(DateConditionMatcher::class, function($app){
   return new DateConditionMatcher();
});

$this->app->singleton(TimeConditionMatcher::class, function($app){
   return new TimeConditionMatcher();
});

$this->app->singleton(LocationConditionMatcher::class, function($app){
    return new LocationConditionMatcher($app->make(LocationServiceInterface::class));
});

总的来说,我认为我遗漏了一些东西,它会以更优雅的方式完成,但现在我把它当作一个答案。如果您有更好的解决方案,请分享:)