为了使我的应用程序正常工作,我需要定期同步来自外部服务的数据(可以是 API,也可以是简单的文本文件,但目前它是 API)。
由于这需要一次创建/更新许多实体,因此我需要创建一个域服务。但是,我还需要创建一些包含远程 API 响应的 DTO,对吗?
这个逻辑应该去哪里呢?我应该有以下目录结构吗:
Domain -
Model - // my set of entities and repository interfaces are here
....
Synchronization -
RunSynchronizationService.php // domain service
Application
Synchronization -
SynchronizeData.php // application service
SynchronizationDataSourceInterface.php // used by application service
MySpecificRemoteApiDataSource.php // this implements the interface above
SynchronizationDataSourceResponse.php // this would be returned by each call of SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Infrastructure -
MyConcreteImplementationOfModelEntityRepository.php
当我想要同步数据时,我只需调用Application\Synchronization\SynchronizeData的sync方法,该方法将采用SynchronizationDataSourceInterface的具体实现,调用其方法,并验证返回的SynchronizationDataSourceResponse对象,然后将它们传输到Domain\Model\Synchronization\运行同步服务?
或者我应该删除 RunSynchronizationService (域服务)并让应用程序服务 (SynchronizeData.php) 在同步过程的每个步骤创建/更新域实体?
通常,当遇到有关外部服务接口应该位于何处的问题时,我会尝试将其视为另一个存储库。 我在这里选择的抽象级别将在很大程度上取决于谁将使用该服务(只是该项目的域/应用程序层?其他项目?),是否存在不同版本/供应商的服务,以及如何使用哪个服务确定了。
对于您的示例,我假设该应用程序是唯一直接使用同步服务的应用程序。 共享服务需要进一步隔离公共端点(例如接口和输出对象),以避免将不必要的对象溢出到其他项目中。
但在这种情况下,为了将该服务视为另一个存储库,我将为其放置接口以及域期望并在域中使用的标准输出。
“验证”的含义在您的描述中有点模糊,所以我将尝试在这里攻击不同的观点。 一项或全部都可以申请。
如果验证要求您与域数据进行比较,它可能应该驻留在
RunSynchronizationService.php
模块中。 该模块似乎负责获取同步数据并将其应用到您的域。
如果验证是针对从同步服务调用返回的数据,并且不需要直接访问域对象图,我会将该验证放在接口的服务实现上,并在服务接口上公开该验证调用。 要处理同步服务的多个版本(例如 VersionA、VersionB 等)中的验证相同的情况,您可以使用继承和覆盖,或同步服务的通用辅助函数等。在下面的示例中,我使用了继承。
您可能需要进行这两种验证。 首先检查与域无关的同步数据问题(在已实现的类上),然后针对域中的业务规则进行检查(在
RunSynchronizationService
中)。 但是,当您在界面上公开同步数据验证调用时,这两个调用可能都会发生在 RunSynchronizationService
中。
应用程序层应负责创建服务实例 (
MySpecificRemoteApiDataSource
),并将其作为 RunSynchronizationService.php
传递到 SynchronizationDataSourceInterface
模块中。 如果有多个版本,应用程序层可能会负责选择哪个版本(也许是从配置中),并使用工厂。
但这又在很大程度上取决于该同步服务的范围。 如果您有依赖它的外部项目,您可能希望服务层本身的工厂部分,以便其他每个项目都使用相同的选择方法进行操作。
Domain -
Model - // my set of entities and repository interfaces are here
....
Synchronization -
RunSynchronizationService.php // domain service
SynchronizationDataSourceInterface.php // used to define the contract associated with a sync service
SynchronizationDataSourceResponse.php // this would be returned by each call of SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Application -
Synchronization -
SynchronizeData.php // application service - Uses a factory or some means of determining which version to use and introduce the domain to the data point.
Infrastructure -
MyConcreteImplementationOfModelEntityRepository.php
Synchornization -
VersionA -
MySpecificRemoteApiDataSource.php // Implements SynchronizationDataSourceInterface.php, inherits from SyncApiDataSourceBase.php
SyncApiDataSourceBase.php // Common logic for sync goes here, such as validation.