代码之家  ›  专栏  ›  技术社区  ›  toxaq

在多层体系结构中,应在何处转换表示值?

  •  5
  • toxaq  · 技术社区  · 15 年前

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

    这意味着我需要重复地将时间属性转换为正确的用户时区。重复总是坏代码或更好方法的标志,所以我试图制定出最佳的实现策略。虽然这是一种有效的表示逻辑,但我的想法是不同的,因为似乎模型应该知道当前用户的正确值。到目前为止,我的想法是:

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

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

    3. 为仅存在于表示层中的模型编写扩展方法。这看起来很干净,但不具有说服力。

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

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

    我对这些策略或任何其他我应该或可能用来替代这些策略的观点感兴趣。

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

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

    1 回复  |  直到 14 年前
        1
  •  2
  •   henginy    15 年前

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

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

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

    我不知道这种方法是否适用于您,但它受到您的策略的启发,我认为设计的其他部分以这种方式运行更平稳。此外,到当地时间的转换仍由客户自行决定。缺点是必须转换客户机中的所有时间值,但在我看来,这是消除重复数据和静态方法的必要条件。