【问题标题】:Where should conversion of presentation values be made in multi-tier architecture?在多层架构中应该在哪里进行表示值的转换?
【发布时间】:2012-05-12 04:43:40
【问题描述】:

我正在构建一个多语言、多时区和 n 层的应用程序。所有日期都以 UTC 格式存储在数据库中,所有模型对象都使用 UTC 时间填充。但是 UTC 时间永远不会显示(除非用户碰巧将他们的时区设置为 UTC)。

这意味着我需要反复将时间属性转换为正确的用户时区。重复总是错误代码或更好方法的标志,因此我试图制定最佳实施策略。尽管这实际上是表示逻辑,但我的想法已经发生了变化,因为似乎模型应该知道当前用户的正确值。到目前为止,我的想法是:

  1. 使用静态帮助器类,然后在每次使用模型的属性时调用它。这似乎容易出错或被遗忘,而且计算起来很麻烦。

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

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

  4. 在模型层中为转换创建一个接口。在表示层实现助手并给模型层实现。然后模型具有使用接口转换时间的属性。这似乎应该打破关注点分离,但似乎没有。如果您有一个默认转换器,那么您不必担心会出现空对象异常,但是模型层(目前是 POCO)将需要一个用于转换帮助器的容器,这看起来很混乱。

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

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

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

我仍然愿意接受更好的解决方案和对我当前解决方案的批评。

【问题讨论】:

    标签: design-patterns architecture timezone


    【解决方案1】:

    我假设是您的模型层知道用户的时区,因此由模型层来转换时间属性。否则,您将不得不让表示层知道时区,并在那里转换每个时间值。

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

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

    我不知道这种方法是否适合你,但它受到了你的策略的启发,我认为其他设计以这种方式运行起来会更顺畅。此外,转换为本地时间仍由客户支配。缺点是必须转换客户端中的所有时间值,但在我看来,这是一种必要的邪恶,以换取摆脱数据重复和静态方法。

    【讨论】:

    • 我想这是我的一些观点,我的模型层是否应该知道用户所在的时区?目前没有。我的内部争论是这是一个表示层还是模型层的决定。用户 POCO 存储时区,但用户 POCO 没有其他 POCO 的时间属性。因此,我将一个 POCO 的值显示绑定到另一个之前不需要的值的显示......
    • 太好了,谢谢。我明白你在说什么,对我来说,这确实是两个“必要的邪恶”之间的折腾。由于我喜欢简单的消费方式(并且因为我目前是唯一一个致力于此的人),我会暂时坚持我的方式,但我认为你的方式同样有效,而且肯定更透明/可读。
    猜你喜欢
    • 2017-11-30
    • 2012-06-05
    • 1970-01-01
    • 2011-01-27
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 2023-03-21
    相关资源
    最近更新 更多