AppServiceProvider中基于模型解析服务
Resolving service based on model in AppServiceProvider
给你一个简短的看法:我正在尝试根据条件进行重定向。如果请求满足给定目的地的条件,您将重定向到特定目的地。
我有 Destination
模型,它有很多条件(条件模型)。我有许多扩展基本条件模型的条件,如 DateCondition
、LocationCondition
等(由多态关系构成)。每个条件类型都应该有 '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));
});
总的来说,我认为我遗漏了一些东西,它会以更优雅的方式完成,但现在我把它当作一个答案。如果您有更好的解决方案,请分享:)
给你一个简短的看法:我正在尝试根据条件进行重定向。如果请求满足给定目的地的条件,您将重定向到特定目的地。
我有 Destination
模型,它有很多条件(条件模型)。我有许多扩展基本条件模型的条件,如 DateCondition
、LocationCondition
等(由多态关系构成)。每个条件类型都应该有 '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));
});
总的来说,我认为我遗漏了一些东西,它会以更优雅的方式完成,但现在我把它当作一个答案。如果您有更好的解决方案,请分享:)