我正在构建一个多语言,多时间和n层的应用程序。所有日期都以UTC格式存储在数据库中,所有模型对象都以UTC时间填充。但是,UTC时间永远不会显示(除非用户碰巧将其时区设置为UTC)。
这意味着我需要重复地将时间属性转换为正确的用户时区。重复始终是糟糕代码的标志或更好的方式,所以我试图找出最佳策略来实现。虽然这是有效的表示逻辑,但我的想法已经变化,因为模型似乎应该知道当前用户的正确值。到目前为止,我的想法是:
使用静态助手类,然后每次使用模型的属性时调用它。这似乎容易出错或被遗忘,使得计算变得麻烦。
将模型对象包装在viewmodel对象中。这同样很麻烦,尤其是在处理对象列表时。
为仅存在于表示层中的模型编写扩展方法。这看起来更干净但不直观。
在模型图层中为转换创建一个界面。在表示层中实现帮助程序,并为模型层提供实现。然后,模型具有使用接口转换时间的属性。这似乎应该打破关注点的分离,但似乎并没有。如果您有一个默认转换器,那么您不必担心获取空对象异常,但是模型层(当前为POCO)需要一个转换助手的容器,这似乎很麻烦。
在模型上创建转换为本地时区方法并传入当前时区。
我对这些策略或任何其他我应该或可以用来代替这些策略的意见感兴趣。
更新 我目前所做的是在模型层中创建ITimeConvertor和ITimeConvertorFactory。然后我创建了这些的默认实现,只返回原始日期值。在模型层中,我为最初在模型上的每个现有UTC属性添加了本地时间属性。在这些属性中,我使用工厂来获取转换器并在getter和setter中以每种方式转换UTC值。我必须在模型层(我不太喜欢)中添加一个静态设置类作为存储当前timeconvertor工厂的地方。在Web应用程序部分中,我将ITimeConvertorFactory和ITimeConvertor实现为WebTimeConvertorFactory和WebTimeConvertor。 WebTimeConvertor知道会话和当前用户,因此可以获取当前时区。 WebTimeConvertorFactory创建WebTimeConvertors。当应用程序启动时(global.asax中的application_onstart),我创建工厂并将其传递给模型层静态设置属性。这允许我的模型层能够转换本地时间,而数据层只知道UTC日期属性。这也意味着我可以将本地时间直接传递到模型中并准确转换,前提是消费应用程序已经提供了转换器工厂。由于UTC属性未更改,它们仍可在应用程序内的任何位置使用。 虽然它看起来像很多代码,但我发现这个解决方案一旦实现就相当干净,因为它允许服务的其他消费者无论如何都要实现他们的时间转换(如果有的话),同时合理地保持模型属性的消耗明显。
我仍然愿意接受更好的解决方案并批评我目前的解决方案。
答案 0 :(得分:2)
我认为你的模型层知道用户的时区,因此由模型层来转换时间属性。否则,您必须让表示层知道时区,并在那里转换每个时间值。
在模型层中转换时间值可以在表示层中使用它们而无需任何转换,所以我认为这样很干净。例如,您可以在开头使用转换时间初始化对象(POCO)。但要注意在模型中重新转换它们,忘记它们已经初始化为当地时间。此外,如果用户可以编辑时间值,则需要在保存之前将它们转换回UTC时间。
<强>更新强>
经过一番思考,我认为UTC时间是模型的一部分,而本地时间是这个模型的一个视图,因此转换任务更多地属于表示层(以不同意我自己为代价)。使用相同的思维过程,将本地时间属性与UTC时间一起实质上是重复的,并且转换仍然在模型层中。为了克服这个问题,您可能在用户POCO中具有只读UTCToLocalTimeConverter
- 类型属性,该属性使用时区初始化(这也消除了对静态方法的需要)。然后,页面中对时间属性的所有调用都将包含在转换器的ConvertToLocalTime
方法中,该方法可通过用户访问。如果您愿意,也可以将转换器实例直接放在Session
中。
我不知道这种方法是否对您有用,但它的灵感来自您的策略,我认为其余的设计运行起来更顺畅。转换到本地时间仍然是客户可以使用的。缺点是必须转换客户端中的所有时间值,但在我看来这是摆脱数据复制和静态方法的必要之恶。