Clean Architecture 中一个控制器可以调用多个用例(交互器)吗?
Can one controller call multiple usecase (interactor) in Clean Architecture?
我正在设计一个带有 spring 后端的移动应用程序。
在我的移动应用程序中,我有一个随机播放按钮。当用户单击按钮时,我从 GPS 获取用户的当前位置并发送请求,然后使用此位置信息查找当前用户附近的用户。
顺便说一下,shuffle 和 filter 用例使用相同的用例,唯一的区别是当 shuffle 时我应用默认过滤器,如所有年龄、所有距离等。
~~Shuffle/Filter请求~~
{
interestedGenders: ["WOMAN"]
minDistance: 1,
maxDistance: 100,
minAge: 18,
maxAge: 65,
latitude: 31.4,
longitude: 27.1
}
Okey,现在我的问题是我不想 track/update 实时用户位置所以我想当用户洗牌(或过滤器)时我已经有用户位置所以首先我更新数据库中的用户位置然后我使用此位置信息通过其他过滤器(性别、年龄等)查找附近的用户
我在 mongo 数据库中有 3 个简单集合(帐户、配置文件和用户位置)
~~个人资料文件(简体)~~
{
id: "xxx",
accountId: "yyy",
gender: "MAN",
interestedGenders: ["WOMAN"]
}
~~ userLocation 文件~~
{
id: "zzz"
accountId: "yyy",
location: { type: "Point", coordinates: [31.4, 27.1] }
lastUpdated: "2020-10-10T00:59:37.154Z"
}
这是我使用的代码。首先我执行更新用户位置用例。如果用户在数据库中没有记录,则更新位置用例创建记录,否则更新用户位置。然后我发现用户符合条件。
@ApiController
@AllArgsConstructor
public class FilterProfilesController {
private final UpdateUserLocationUseCase updateUserLocationUseCase;
private final FilterProfilesUseCase filterProfilesUseCase;
@PostMapping("/profiles/filter")
public ResponseEntity<BaseResponse> filterProfiles(@AuthenticationPrincipal AccountId accountId, @RequestBody FilterProfilesRequest request) {
var userLocation = new Location(new Latitude(request.getLatitude()), new Longitude(request.getLongitude()));
updateUserLocationUseCase.execute(new UpdateUserLocationUseCase.Command(accountId, userLocation), () -> {
});
// Conversions from request to value objects (simplified)
var query = new FilterProfilesUseCase.Query(accountId, userLocation, interestedGenders, ageRange, distanceRange);
var presenter = new FilterProfilesPresenter();
filterProfilesUseCase.execute(query, presenter);
return presenter.getViewModel();
}
}
最好的设计方法是什么?
我如何解耦更新位置用例(来自 FilterProfilesController)但仍然在过滤用例之前调用?
我应该写一个自定义方面还是什么?
一些问题的答案
问:为什么我没有将用户位置信息放入个人资料集合中?
A: 因为我们在用户注册的时候没有得到这个信息。所以位置字段保持为空,直到用户使用随机播放或过滤器页面并且我在 mongo 数据库中使用地理空间查询所以我猜这可能会导致错误。
加上配置文件对象已经有很多字段,我认为分离用户位置为未来的用例提供了很大的灵活性。
通常建议您将应用程序的“写入”端与“读取”端分开。
您可能希望独立扩展查询服务,因为写入与读取不成比例。对于每次写入(GPS 位置),您可能需要执行 10 次或 100 次查询。
在您的示例中,您可能会在第一时间收到 GPS 位置,但允许用户使用不同的过滤器组合执行多个查询。假设您自动收集用户的 GPS 位置,它可能不会在查询之间改变。
您的应用程序的域模型通常不适合查询。您通常会构造相同数据(写入端)的多种表示形式,以满足不同 API(读取端)所需的响应格式。您可以结合使用 Domain Events
和 Subscribers
,甚至可以单独为查询端创建一个单独的微服务。
因此,最好将 GPS Location Update
用例与查询分开。它会导致两次调用,但您在 return.
中获得了很大的灵活性
因此,最好让调用者(在本例中为 UI)在请求数据之前先执行更新。这具有额外的好处,您可以异步收集 GPS 更新(作为 ping)以更新用户位置,而不仅仅是在用户请求数据时。
我正在设计一个带有 spring 后端的移动应用程序。
在我的移动应用程序中,我有一个随机播放按钮。当用户单击按钮时,我从 GPS 获取用户的当前位置并发送请求,然后使用此位置信息查找当前用户附近的用户。
顺便说一下,shuffle 和 filter 用例使用相同的用例,唯一的区别是当 shuffle 时我应用默认过滤器,如所有年龄、所有距离等。
~~Shuffle/Filter请求~~
{
interestedGenders: ["WOMAN"]
minDistance: 1,
maxDistance: 100,
minAge: 18,
maxAge: 65,
latitude: 31.4,
longitude: 27.1
}
Okey,现在我的问题是我不想 track/update 实时用户位置所以我想当用户洗牌(或过滤器)时我已经有用户位置所以首先我更新数据库中的用户位置然后我使用此位置信息通过其他过滤器(性别、年龄等)查找附近的用户
我在 mongo 数据库中有 3 个简单集合(帐户、配置文件和用户位置)
~~个人资料文件(简体)~~
{
id: "xxx",
accountId: "yyy",
gender: "MAN",
interestedGenders: ["WOMAN"]
}
~~ userLocation 文件~~
{
id: "zzz"
accountId: "yyy",
location: { type: "Point", coordinates: [31.4, 27.1] }
lastUpdated: "2020-10-10T00:59:37.154Z"
}
这是我使用的代码。首先我执行更新用户位置用例。如果用户在数据库中没有记录,则更新位置用例创建记录,否则更新用户位置。然后我发现用户符合条件。
@ApiController
@AllArgsConstructor
public class FilterProfilesController {
private final UpdateUserLocationUseCase updateUserLocationUseCase;
private final FilterProfilesUseCase filterProfilesUseCase;
@PostMapping("/profiles/filter")
public ResponseEntity<BaseResponse> filterProfiles(@AuthenticationPrincipal AccountId accountId, @RequestBody FilterProfilesRequest request) {
var userLocation = new Location(new Latitude(request.getLatitude()), new Longitude(request.getLongitude()));
updateUserLocationUseCase.execute(new UpdateUserLocationUseCase.Command(accountId, userLocation), () -> {
});
// Conversions from request to value objects (simplified)
var query = new FilterProfilesUseCase.Query(accountId, userLocation, interestedGenders, ageRange, distanceRange);
var presenter = new FilterProfilesPresenter();
filterProfilesUseCase.execute(query, presenter);
return presenter.getViewModel();
}
}
最好的设计方法是什么?
我如何解耦更新位置用例(来自 FilterProfilesController)但仍然在过滤用例之前调用?
我应该写一个自定义方面还是什么?
一些问题的答案
问:为什么我没有将用户位置信息放入个人资料集合中?
A: 因为我们在用户注册的时候没有得到这个信息。所以位置字段保持为空,直到用户使用随机播放或过滤器页面并且我在 mongo 数据库中使用地理空间查询所以我猜这可能会导致错误。
加上配置文件对象已经有很多字段,我认为分离用户位置为未来的用例提供了很大的灵活性。
通常建议您将应用程序的“写入”端与“读取”端分开。
您可能希望独立扩展查询服务,因为写入与读取不成比例。对于每次写入(GPS 位置),您可能需要执行 10 次或 100 次查询。
在您的示例中,您可能会在第一时间收到 GPS 位置,但允许用户使用不同的过滤器组合执行多个查询。假设您自动收集用户的 GPS 位置,它可能不会在查询之间改变。
您的应用程序的域模型通常不适合查询。您通常会构造相同数据(写入端)的多种表示形式,以满足不同 API(读取端)所需的响应格式。您可以结合使用 Domain Events
和 Subscribers
,甚至可以单独为查询端创建一个单独的微服务。
因此,最好将 GPS Location Update
用例与查询分开。它会导致两次调用,但您在 return.
因此,最好让调用者(在本例中为 UI)在请求数据之前先执行更新。这具有额外的好处,您可以异步收集 GPS 更新(作为 ping)以更新用户位置,而不仅仅是在用户请求数据时。