Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在何处放置';逻辑';从一个人身上合成全名';s名称部件(在MVC应用程序中)_C#_Oop_Architecture_Naming Conventions - Fatal编程技术网

C# 在何处放置';逻辑';从一个人身上合成全名';s名称部件(在MVC应用程序中)

C# 在何处放置';逻辑';从一个人身上合成全名';s名称部件(在MVC应用程序中),c#,oop,architecture,naming-conventions,C#,Oop,Architecture,Naming Conventions,我有3个viewmodels,它们都必须显示一个人的全名 现在我当然可以在所有3个viewmodels中复制GetFullName()函数,但这并不是那么简单 但是,我该把计算人员全名的逻辑放在哪里呢 我是否创建了一个包含四个字段的接口(我们计算 四个字段的全名)并在所有3个字段中实现接口 查看模型并创建一个“PersonHelper”类,该类接受 接口并返回字符串 创建自己的类的逻辑是否太少 我是否为包含逻辑的3个viewmodels创建基类?(但是如果我想在API函数中使用该函数呢?) 助

我有3个viewmodels,它们都必须显示一个人的全名

现在我当然可以在所有3个viewmodels中复制
GetFullName()
函数,但这并不是那么简单

但是,我该把计算人员全名的逻辑放在哪里呢

  • 我是否创建了一个包含四个字段的接口(我们计算 四个字段的全名)并在所有3个字段中实现接口 查看模型并创建一个“PersonHelper”类,该类接受 接口并返回字符串
  • 创建自己的类的逻辑是否太少
  • 我是否为包含逻辑的3个viewmodels创建基类?(但是如果我想在API函数中使用该函数呢?)
  • 助手是否可以称为PersonService,因为在过去,它是放置在Person类本身中的逻辑,但现在我们将数据类与行为分开(因此可能是“PersonBehavior”?)
这么简单的事情,这么多的方法来实现它


您对此有何看法?

对于所有三种ViewModels,使用基类怎么样

public string FirstName {get;set;}
public string LastName {get;set;}
public string FullName {get{return String.Format("{0} {1}",FirstName,LastName);}}

使用基类可以最大限度地减少所有三个ViewModel的代码重复。这也是一个简单的解决方案,很容易理解(由未来的开发人员)并且很快就可以更改。API是否会限制这种功能性?

我的第一个想法是询问您的视图模型是直接存储用户数据,还是公开包含用户名的类。如果你不是,我可能会将用户名数据重新分配到它自己的类中(以及其他用户数据,如果这对你的应用程序有意义,那么将FormattedFullName属性放入该类中)

public class ViewModel1()
{
    public PersonData myPerson {get; set;}
    // other properties
}

public class ViewModel2()
{
    public PersonData myPerson {get; set;}
    // other properties
}

public class PersonData()
{
    public string forename { get; set; }
    public string surname { get; set; }
    public string FormattedFullName 
    { 
        get 
        { 
            return string.Format("{0} {1}", forename, surname); 
        } 
    }
    // other properties
}

我们有一个“formatter”类,它处理某些数据的格式化,例如在多行或单行上显示地址行

我们这样称呼它:
Formatter.FormatAddress(address)
其中address是一个模型类实例。您可以轻松地将这种逻辑应用于您的全名


另一种选择是编写自己的HtmlHelperExtensions,这样您就可以执行
Html.FormatFullName(Model.FirstName,Model.LastName)


将html添加到HtmlHelperExtensions中也不是不好的做法,因此这很好。

我会让我的3个视图模型实现一个通用接口IFormattablePerson,其中包含用于计算全名的字段并依赖String.Format

这是一种非常方便的扩展显示的方法,只需在自定义格式化程序中添加新的字符串格式即可

这将导致以下情况:

视图模型必须实现的公共接口:

public interface IFormattablePerson: IFormattable
{
string FirstName{get;set;}
string LastName{get;set;}
}   
每个视图模型中都有相同的ToString()实现,它永远不会改变

public string ToString(string format, IFormatProvider formatProvider)
{
    if (formatProvider == null)
        return ToString(format, new FormatProviderIFormattablePerson());
    else
        return (formatProvider.GetFormat(typeof(IFormattablePerson)) as ICustomFormatter).Format(format, this, formatProvider);
}
这将使用FormatProvider和CustomFormatter作为IFormattablePerson。 然后,您只需要在CustomFormatter中添加并实现新格式

public class FormatProviderIFormattablePerson : IFormatProvider
{
    // String.Format calls this method to get an instance of an
    // ICustomFormatter to handle the formatting.
    public object GetFormat(Type service)
    {
        if (service == typeof(IFormattablePerson))
        {
            return new CustomFormatterIFormattablePerson();
        }
        else
        {
            return null;
        }
    }
}

public class CustomFormatterIFormattablePerson : ICustomFormatter
{
    public string Format(string format, object arg, IFormatProvider provider)
    {
        if (string.IsNullOrEmpty(format))
            format = "full";

        if (arg is IFormattablePerson)
        {
            IFormattablePerson t = (IFormattablePerson) arg;
            switch (format)
            {
                case "f": 
                    return t.FirstName;

                case "l": 
                    return t.LastName;

                case "full": 
                default:
                    return string.Format("{0} {1}",
                        t.FirstName,
                        t.LastName).Trim();
            }                   
        }
        if (arg is IFormattable)
            return string.Format(String.Format("{{0:{0}}}",format), arg);
        else
            return arg.ToString();
    }
}

如果你在做DDD,最好在域模型上实现它。从你提到的选项中,我会选择创建一个接口和PersonHelper(PersonService,只是名称约定)。啊哈,我不熟悉DDD,所以我可能不:-)OP没有提到使用HTML,因此,HtmlHelperExtension的想法现在可能是有效的-这是一个布局底层类的问题,而不是输出到HTML或任何其他显示技术。好的,我把这个示例放在“helper”类代码中,对吗?这是一个扩展方法()。必须导入命名空间(
使用extensions.namespace;
)才能使用它。在视图中使用它们的最佳位置是在视图文件夹的Web.config中。@ZombieSheep我认为问题的答案是不应该在基础类中对此进行建模。这是一个显示一些值的问题。这是视图逻辑,应该在视图中。我提供了一些以可重用的方式实现这一点的解决方案。API就是一个例子,我的上下文中没有任何3个ViewModel,我确实需要全名逻辑。您的基类不必是“ViewModel”,它可以是继承链中更高的任何类,因此您的API中的返回类型可以继承这个类也是一样的……啊,好吧,但我对大型继承树的经验是,它们会变得泛型或太大。然后,在本例中,我从包含业务逻辑的基类继承了viewmodels,这在我看来并不奇怪……我注意到您在问题中说您“将数据类与行为分离”。我认为“全名”属性不是行为,而是恰好从其他数据位派生的对象的属性。你有没有理由认为不应该将此添加到Person类中?很好。因此,在本例中,原始OO原则用于创建具有数据属性和行为的新对象(FormattedFullName)。看起来不错。你是对的,在这种情况下,这不是真正的行为。我提到这一点的原因是,所有OO示例都讨论了包含行为的类(针对策略模式、多态性等),而现在所有的代码示例都显示了POCO类,并且行为被放在单独的类中(关注点分离、实体中的“s”等),但将不在POCO类中的东西放在哪里(行为)大部分是看不见的(示例代码之外)。因此,在本例中,我可以将其添加到Person类中,但我的想法更广泛:-)
public class FormatProviderIFormattablePerson : IFormatProvider
{
    // String.Format calls this method to get an instance of an
    // ICustomFormatter to handle the formatting.
    public object GetFormat(Type service)
    {
        if (service == typeof(IFormattablePerson))
        {
            return new CustomFormatterIFormattablePerson();
        }
        else
        {
            return null;
        }
    }
}

public class CustomFormatterIFormattablePerson : ICustomFormatter
{
    public string Format(string format, object arg, IFormatProvider provider)
    {
        if (string.IsNullOrEmpty(format))
            format = "full";

        if (arg is IFormattablePerson)
        {
            IFormattablePerson t = (IFormattablePerson) arg;
            switch (format)
            {
                case "f": 
                    return t.FirstName;

                case "l": 
                    return t.LastName;

                case "full": 
                default:
                    return string.Format("{0} {1}",
                        t.FirstName,
                        t.LastName).Trim();
            }                   
        }
        if (arg is IFormattable)
            return string.Format(String.Format("{{0:{0}}}",format), arg);
        else
            return arg.ToString();
    }
}