前端整洁架构,你了解多少?( 六 )


重要的是要记住,外部服务必须适应我们的需求 。因此,在应用层中,我们将描述不仅仅是用例本身,还包括与这些外部服务进行交互的接口:端口 。
首先,端口应该方便我们的应用 。如果外部服务的API不符合我们的需求,就需要编写一个适配器 。
考虑一下将需要的服务:

  • 一个支付系统;
  • 一个用于通知用户有关事件和错误的服务;
  • 一个用于将数据保存到本地存储的服务 。

前端整洁架构,你了解多少?

文章插图
需要的服务现在讨论的是这些服务的接口,而不是它们的实现 。在这个阶段,对于我们来说描述所需行为非常重要,因为这是我们在应用层中描述场景时所依赖的行为 。
如何实现这个行为暂时还不重要 。这使得我们可以将关于使用哪些外部服务的决策推迟到最后,从而使代码的耦合度最小化 。我们稍后会处理实现部分 。
还要注意,我们将接口按功能拆分 。与支付相关的所有内容都在一个模块中,与存储相关的内容在另一个模块中 。这样做将更容易确保不混淆不同第三方服务的功能 。
支付系统接口饼干商店是一个简单的示例,因此支付系统将很简单 。它有一个 tryPay 方法,该方法将接受需要支付的金额,并作为响应发送确认 。
// application/ports.tsexport interface PaymentService {tryPay(amount: PriceCents): Promise<boolean>;}这里没有进行错误处理,因为错误处理是一个独立的大型主题,不是本次的讨论范围 。
通常支付是在服务器上进行的,但这只是一个示例,所以在客户端上完成所有操作 。可以轻松地通过与 API 通信而不是直接与支付系统通信 。这种更改只会影响到这个用例,其余的代码将保持不变 。
通知服务接口如果出现问题,我们必须告诉用户 。可以通过不同的方式通知用户 。可以使用用户界面,可以发送电子邮件,可以用手机短信来提醒用户 。
一般来说,通知服务最好也是抽象的,这样就不必考虑具体实现的细节 。
让它接收消息并以某种方式通知用户:
// application/ports.tsexport interface NotificationService {notify(message: string): void;}本地存储接口我们将把新订单保存在本地存储库中 。
该存储可以是任何东西:Redux、MobX、whatever-floats-your-boat-js 。该存储库可以分为不同实体的微型存储库,也可以成为所有应用数据的一个大存储库 。现在也不重要,因为这些是实现细节 。
我喜欢将存储接口划分为每个实体的单独存储接口 。用于用户数据存储的单独接口、用于购物车的单独接口、用于订单存储的单独接口:
// application/ports.tsexport interface OrdersStorageService {orders: Order[];updateOrders(orders: Order[]): void;}用例功能根据之前描述的接口和现有领域功能,让我们尝试构建该用例的实现 。正如之前所描述的,脚本将包含以下步骤:
  • 验证数据 。
  • 创建订单 。
  • 支付订单 。
  • 通知问题 。
  • 保存结果 。

前端整洁架构,你了解多少?

文章插图
图中自定义脚本的所有步骤首先,声明要调用的服务模块 。TypeScript 会提示我们没有在适当的变量中实现接口,但现在没关系 。
// application/orderProducts.tsconst payment: PaymentService = {};const notifier: NotificationService = {};const orderStorage: OrdersStorageService = {};现在,我们可以将其视为真实的服务 。可以访问它们的字段,调用它们的方法 。当将用例转换为代码时,这非常方便 。
现在,我们创建一个名为orderProducts的函数 。在函数内部,首先创建一个新订单:
// application/orderProducts.ts//...async function orderProducts(user: User, cart: Cart) {const order = createOrder(user, cart);}这里我们把接口作为行为的契约 。这意味着模块实际上会执行我们期望的操作:
// application/orderProducts.ts//...async function orderProducts(user: User, cart: Cart) {const order = createOrder(user, cart);// 尝试支付订单,如果出现问题,通知用户:const paid = await payment.tryPay(order.total);if (!paid) return notifier.notify("Оплата не прошла


推荐阅读