在多层架构中应该在哪里转换表示值?

tox*_*xaq 5 architecture timezone design-patterns

我正在构建一个多语言,多时间和n层的应用程序.所有日期都以UTC格式存储在数据库中,所有模型对象都以UTC时间填充.但是,从不显示UTC时间(除非用户恰好将其时区设置为UTC).

这意味着我需要重复地将时间属性转换为正确的用户时区.重复始终是糟糕代码的标志或更好的方式,所以我试图找出最佳策略来实现.虽然这是有效的表示逻辑,但我的想法已经变化,因为模型似乎应该知道当前用户的正确值.到目前为止,我的想法是:

  1. 使用静态助手类,然后在每次使用模型的属性时调用它.这似乎容易出错或被遗忘,使得计算变得繁琐.

  2. 将模型对象包装在viewmodel对象中.这同样很麻烦,尤其是在处理对象列表时.

  3. 为仅存在于表示层中的模型编写扩展方法.这看起来更干净但不直观.

  4. 在模型层中为转换创建一个接口.在表示层中实现帮助程序,并为模型层提供实现.然后,模型具有使用接口转换时间的属性.这似乎应该打破关注点的分离,但似乎并没有.如果您有一个默认转换器,那么您不必担心获取空对象异常,但是模型层(当前为POCO)需要一个转换助手的容器,这似乎很麻烦.

  5. 在模型上创建转换为本地时区方法并传入当前时区.

我对这些策略或任何其他我应该或可能用来代替这些策略的意见感兴趣.

更新 我目前所做的是在模型层中创建ITimeConvertor和ITimeConvertorFactory.然后我创建了这些的默认实现,只返回原始日期值.在模型层中,我为最初在模型上的每个现有UTC属性添加了本地时间属性.在这些属性中,我使用工厂来获取转换器并在getter和setter中以每种方式转换UTC值.我必须在模型层(我不太喜欢)中添加一个静态设置类作为存储当前timeconvertor工厂的地方.在Web应用程序部分中,我将ITimeConvertorFactory和ITimeConvertor实现为WebTimeConvertorFactory和WebTimeConvertor.WebTimeConvertor知道会话和当前用户,因此可以获取当前时区.WebTimeConvertorFactory创建WebTimeConvertors.当应用程序启动时(global.asax中的application_onstart)我创建工厂并将其传递给模型层静态设置属性.这允许我的模型层能够转换本地时间,而数据层只知道UTC日期属性.这也意味着我可以将本地时间直接传递到模型中并准确转换,前提是消费应用程序已经提供了转换器工厂.由于UTC属性未更改,它们仍可在应用程序内的任何位置使用.虽然它看起来像很多代码,但我发现这个解决方案一旦实现就相当干净,因为它允许服务的其他消费者无论如何都要实现他们的时间转换(如果有的话),同时合理地保持模型属性的消耗明显.

我仍然愿意接受更好的解决方案并批评我目前的解决方案.

hen*_*iny 2

我假设您的模型层了解用户的时区,因此由模型层来转换时间属性。否则,您必须让表示层了解时区,并在那里转换每个时间值。

在模型层中转换时间值将允许在表示层中使用它们而无需任何转换,所以我认为这会很干净。例如,您可以在开始时使用转换后的时间来初始化对象(PO​​CO)。但要小心在模型中重新转换它们,忘记它们已经初始化为本地时间。此外,如果用户可以编辑时间值,则您需要在保存之前将它们转换回 UTC 时间。

更新: 经过更多思考,我认为 UTC 时间是模型的一部分,本地时间是该模型的视图,因此转换职责更多地属于表示层(以不同意我自己为代价)。同样的思路,将本地时间属性与UTC时间放在一起,本质上是重复,转换仍在模型层。为了克服这个问题,您可能UTCToLocalTimeConverter在用户 POCO 中有一个 readonly 类型的属性,它是用时区初始化的(这也消除了对静态方法的需要)。然后,对页面中时间属性的所有调用都将包装在转换器的ConvertToLocalTime方法中,该方法可以通过用户访问。Session如果您愿意,您也可以直接将转换器实例放入其中。

我不知道这种方法是否适合您,但它受到您的策略的启发,并且我认为以这种方式思考设计的其余部分会运行得更顺畅。此外,客户仍可以自行决定是否转换为当地时间。缺点是必须转换客户端中的所有时间值,但在我看来,这似乎是摆脱数据重复和静态方法的必要之恶。