8

假设我的电话号码作为 10 位字符串存储在数据库中:

0000000000

我想在将此电话号码呈现给用户时将其格式化为:

(000) 000-0000

我在处理这种格式的实用程序程序集中有一个扩展方法:

static string ToPhoneNumber(this string value)
{
    return Regex.Replace(value, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
}

我的问题是,我在什么时候应用这种转换?

1)在视图中:

@Model.PhoneNumber.ToPhoneNumber()

2)在视图模型中:

public string FormattedPhoneNumber
{
    get
    {
        return this.PhoneNumber.ToPhoneNumber()
    }
}

3)在控制器中:

userModel.FormattedPhoneNumber = userModel.PhoneNumber.ToPhoneNumber()

4)在域模型中(与#2相同的实现)

5)在服务中(与#3相同的实现)

此外,答案是否取决于它是全局格式化需求(如电话号码)还是单个视图上的孤立一次性格式化?

我会给出我的想法,但不想影响任何答案。

4

7 回答 7

5

我个人喜欢将东西保留在我的 ViewModel 中,因为如果你不这样做,你最终会得到看起来很奇怪的代码。让我们举个例子。

剃刀视图:

@using MyNamespace.Models.Extensions
@model MyNamespace.Models.ViewModels.IndexViewModel

@if (string.IsNullOrWhiteSpace(Model.PhoneNumber) {
   <div> @Model.PhoneNumber.ToPhoneNumber() </div>  
}

与替代方案相比:

剃刀视图:

@model MyNamespace.Models.ViewModels.IndexViewModel

@Model.FormattedPhoneNumber

视图模型:

 public string FormattedPhoneNumber {
     get {
         return PhoneNumber.IsEmpty()
         ? "Not Available"
         : PhoneNumber.ToPhoneNumber();
     }
 }

你绝对可以改进我的代码,但关键是它可以让你的视图更简单,以免被分支逻辑弄得一团糟。

此外,我从未声称自己是圣人,所以我并不总是遵循自己的建议,但我应该这样做。照我说的做,不要照我做的:)

于 2013-02-14T15:37:22.317 回答
4

我认为决定如何显示数据是视图的责任。因为只有视图知道可用于呈现的内容。另一方面,在控制器中可能更容易做到这一点。控制器会知道用户的语言环境。总的来说,我认为这没什么区别。

于 2013-02-14T15:25:13.943 回答
2

首先,对于一般的架构模式,尤其是那些处理“关注点分离”的架构模式,最终的仲裁者始终是“我的场景中最好的方法是什么” - 我坚信教条地遵守一组规则而不考虑你的自己的计划和需求是一种可怕的做法。更不用说这里没有明确的共识:根据您的 XYZ 类型(MVC、MVP、MVVM),您会发现对互联网上所有内容的反对意见。

也就是说,我对这个问题的快速回答是“使用你的判断力”。

“在视图中”的论据:

  • 它处理演示,因此它是视图的责任

“在视图模型中”的参数:

  • 通常,视图模型的作用是提供模型的“准备数据绑定”表示 - 因此,将模型数据转换为视图可直接使用的形式是视图模型的责任

模型参数:

  • 这可能是模型数据的一种过于常见的表示;因此,在 DRY 之后,模型将承担此表示的责任

控制器的参数:

  • ...好吧,这里想不出一个合理的。控制器通常对动作做出响应,因此证明它属于这里是一个延伸。

我要说明的一点是,只要您系统的一个点接受并承担责任,并且该责任仅由该组件/层/类处理,您就已经完成了主要目标,即防止稀释/重复/低凝聚力。

我个人的意见,fwiw,可能会落在视图或视图模型上。如果这是 WPF,我几乎肯定会说视图(通过可用于 wpf 数据绑定的格式提供程序)。在网络世界中,我可能会倾向于这种观点,尽管存在模型的有力论据 - 假设您现在想通过 REST/JSON/etc 服务公开这些数据:您可以轻松处理此更改(假设您想要返回格式化的数据,即)

TL/DR:这真的取决于;遵循常识并使用您的判断。将所有相关逻辑放在一个地方是重要的部分,并质疑任何教条/命令式的“你应该”陈述。

于 2013-02-14T15:58:28.817 回答
0

这取决于您对 ViewModel 的定义,您是否遵循(自创的)MVCVM * 方法,除了域模型之外,您还有一个特定于您的视图的 ViewModel?

如果是这样,VM 肯定可以包含格式化逻辑,这就是首先拥有这个 View Model 来为 View 建模的全部意义。所以选项2。

也就是说,这背后的原因是,如果你像这样格式化,你自己的格式化将开始遵循 DRY 原则:

@Regex.Replace(Model.PhoneNumber, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");

由于您有扩展方法,因此在您的视图中调用格式化程序根本不是什么大问题,但我仍然更喜欢在专用 VM 中执行此操作。

如果您的虚拟机实际上只是包含原始数据的域模型(请参阅,模式 1),那么它肯定应该在您的视图中,所以选项 1。请注意,如果您使用此模式,我建议反对它,因为它使您的视图与低级对象强耦合,您最好将其抽象为您需要的内容,以确保域模型 + 视图模型之间的耦合实际上是强的(即在编译时编译,而不是运行时编译!)。

最重要的是 - 这当然应该进入您的域模型。

*模型、视图、控制器、视图模型。ViewModel 包含要在您的视图中使用的数据,以它需要的格式。

于 2013-02-14T15:37:56.210 回答
0

我会把它放在视图模型中而不是视图中。该视图旨在仅将数据/信息呈现给最终用户。保持关注点分离可确保每个对象尽可能独立。如果您将格式化的数字传递给视图,则视图不关心要显示的内容,只需显示格式化的数字。

于 2013-02-14T15:38:10.490 回答
0

我认为这是建模,而不是格式化。如果接收应用程序需要重新格式化这些字段的顺序、间距或大小写,它必须首先将单个字段拆分为几个单独的字段。

这应该是服务层的责任。我们说的是模式,而不是格式。该应用程序要求将字段拆分为其数据合同的一部分。发生这种拆分的位置应该在您的应用程序使用的应用程序服务层中。

服务层应该尝试通过模式将元数据添加到信息中。

例如,如果我从这样的数据合同中收到电话号码:1234567890

演示要求如下:(123) 456 – 7890

服务层应该将电话号码分解为其元素

<PhoneNumber>
<CountryCode>1</CountryCode>
<Area>123</Area>
<Prefix>456</Prefix>
<LineNumber>7890</LineNumber>
</PhoneNumber>
于 2013-02-14T16:19:26.207 回答
-1

选项 1 是最好的,其次是 2。在控制器中,您实际上应该删除格式以将其发送到服务层,因此域模型和服务模型都不知道格式。

于 2013-02-14T15:32:15.880 回答