这个模式叫什么?

3

当你在构造函数中给一个对象传递参数,并且该对象使用该参数填充其字段时,这种模式被称为什么?

例如:

/// <summary>
/// Represents a user on the Dream.In.Code website.
/// </summary>
public class User
{       
    /// <summary>
    /// Load a user by providing an ID.
    /// </summary>
    /// <param name="ID">A user's individual ID number.</param>
    public User(string ID)
    {
        WebClient webClient = new WebClient();
        string htmlSource = webClient.DownloadString(new Uri(String.Format("http://www.dreamincode.net/forums/xml.php?showuser={0}",ID)));
        XDocument xml = XDocument.Parse(htmlSource);

        var profileXML = xml.Element("ipb").Element("profile");

        //Load general profile information.
        this.ID = profileXML.Element("id").Value;
        this.Name = profileXML.Element("name").Value;
        this.Rating = profileXML.Element("rating").Value;
        this.Photo = profileXML.Element("photo").Value;
        this.Reputation = profileXML.Element("reputation").Value;
        this.Group = profileXML.Element("group").Element("span").Value;
        this.Posts = profileXML.Element("posts").Value;
        this.PostsPerDay = profileXML.Element("postsperday").Value;
        this.JoinDate = profileXML.Element("joined").Value;
        this.ProfileViews = profileXML.Element("views").Value;
        this.LastActive = profileXML.Element("lastactive").Value;
        this.Location = profileXML.Element("location").Value;
        this.Title = profileXML.Element("title").Value;
        this.Age = profileXML.Element("age").Value;
        this.Birthday = profileXML.Element("birthday").Value;
        this.Gender = profileXML.Element("gender").Element("gender").Element("value").Value;

        //Load contact information.
        var contactXML = xml.Element("ipb").Element("profile").Element("contactinformation");
        this.AIM = contactXML.XPathSelectElement("contact[title='AIM']/value").Value;
        this.MSN = contactXML.XPathSelectElement("contact[title='MSN']/value").Value;
        this.Website = contactXML.XPathSelectElement("contact[title='Website URL']/value").Value;
        this.ICQ = contactXML.XPathSelectElement("contact[title='ICQ']/value").Value;
        this.Yahoo = contactXML.XPathSelectElement("contact[title='Yahoo']/value").Value;
        this.Jabber = contactXML.XPathSelectElement("contact[title='Jabber']/value").Value;
        this.Skype = contactXML.XPathSelectElement("contact[title='Skype']/value").Value;
        this.LinkedIn = contactXML.XPathSelectElement("contact[title='LinkedIn']/value").Value;
        this.Facebook = contactXML.XPathSelectElement("contact[title='Facebook']/value").Value;
        this.Twitter = contactXML.XPathSelectElement("contact[title='Twitter']/value").Value;
        this.XFire = contactXML.XPathSelectElement("contact[title='Xfire']/value").Value;

        //Load latest visitors.
        var visitorXML = xml.Element("ipb").Element("profile").Element("latestvisitors");
        this.Visitors = (from visitor in visitorXML.Descendants("user")
                        select new Visitor(){
                            ID = visitor.Element("id").Value,
                            Name = visitor.Element("name").Value,
                            Url = visitor.Element("url").Value,
                            Photo = visitor.Element("photo").Value,
                            Visited = visitor.Element("visited").Value,
                        }).ToList();

        //Load friends.
        var friendsXML = xml.Element("ipb").Element("profile").Element("friends");
        this.Friends = (from friend in friendsXML.Descendants("user")
                        select new Friend()
                        {
                            ID = friend.Element("id").Value,
                            Name = friend.Element("name").Value,
                            Url = friend.Element("url").Value,
                            Photo = friend.Element("photo").Value
                        }).ToList();

        //Load comments.
        var commentsXML = xml.Element("ipb").Element("profile").Element("comments");
        this.Comments = (from comment in commentsXML.Descendants("comment")
                            select new Comment()
                            {
                                ID = comment.Element("id").Value,
                                Text = comment.Element("text").Value,
                                Date = comment.Element("date").Value,
                                UserWhoPosted = new Friend()
                                {
                                    ID = comment.Element("user").Element("id").Value,
                                    Name = comment.Element("user").Element("name").Value,
                                    Url = comment.Element("user").Element("url").Value,
                                    Photo = comment.Element("user").Element("photo").Value
                                }
                            }).ToList();
    } 
}

这种模式叫什么?为了让我的代码更简洁,您是否建议我在创建对象内部的对象时使用这种模式,例如在我的UserWhoPosted变量中。而不是:

UserWhoPosted = new Friend()
{
    ID = comment.Element("user").Element("id").Value,
    Name = comment.Element("user").Element("name").Value,
    Url = comment.Element("user").Element("url").Value,
    Photo = comment.Element("user").Element("photo").Value
}

我将有:

UserWhoPosted = new Friend(myFriendXElementVariable);

只需让它解析所需内容并填充其字段即可。

感谢您的指导。

编辑:阅读了您所有的建议后,我稍微整理了一下代码。您认为这样做更好吗?您会有什么改进意见吗?

感谢您花时间帮助我,我正在努力摆脱不良的编程习惯。

http://pastebin.com/AykLjF2i


谢谢大家提供的所有答案;有趣的是,我学得越多,就越意识到自己知道的很少。 :P - delete
7个回答

8

对我来说,这更像是一种反模式:你在构造函数中包含了XML请求、读取和字段初始化。也许你可以使用工厂模式,像这样:

public static class FactoryUser{
public static User GetUserFromXml(Xml){
//your code here
}
}

public static class UserWebrequester{
public static Xml GetXmlUser(id){
}
}

也许您可以添加一些单例以便能够对您的类进行单元测试。

@Matthieu,因为您可以注入依赖项并模拟您的工厂,而使用静态类是不可能的,因为您无法实现接口。 - remi bourgarel
取决于你是否打算进行单元测试^^ 当你的同事只使用静态,因为“当我输入‘myObject.’时它不会出现在Intellisense中”,你就会忘记单元测试。 - remi bourgarel

2

执行以下操作绝对违反了迪米特法则

D = comment.Element("user").Element("id").Value,

你真的不想有这么长的方法调用链。让Friend从其参数中请求值是更好的设计,耦合度更低。

子部件、朋友、访客等应该自己填充,而不是对它们进行操作。这分离了你的关注点。这也使得测试更容易,因为你可以存根顶级参数,而无需深入三层以满足构造函数。


2
我想把它称为 适配器 的一种变体,因为你实际上只是将一些 XML 结构包装成更友好的类型。

2

这不是一个设计模式。设计模式是解决常见问题的方法,例如如何在值更改时保持客户端更新(观察者模式)。这并不是真正的问题,只是语言语法。而且对于你的第二个问题,答案是肯定的。


2

在构造函数中做这样的重型操作是不好的实践,我建议你将构造函数设置为私有,并创建一个静态的Load方法来返回User的实例。我不知道这个模式叫什么。


2

这不是一个“已知的模式”,但可能是您正在使用的一种模式(没有问题...模式只是解决已知问题的常见解决方案)。

然而,由于您的用户类负责加载自身,我认为该类作为DAO(数据访问对象)的工作。

正如其他用户所述,您的构造函数中有太多逻辑。构造函数应该只有创建对象所必需的参数,并尽可能少地执行操作。最好避免在构造函数中抛出异常;因为代码越多,抛出异常的机会就越大,您在构造函数中做的越多,它抛出异常的机会就越大。

现在看看您的类...我看到您的“用户”具有名称、评分等字段。在用户对象的生命周期内,允许它们不填写此类字段吗?创建新用户时可能是这样的。因此,用户不需要拥有此ID,这将使构造函数无效。

尝试创建一个返回新用户的Load静态方法或创建一个工厂。这将有助于您未来的可维护性等方面。

最后,请尝试查看仓储模式。您可以使用它来维护您的用户和其他对象,而不是使用简单工厂。


0
在你的例子中,我更喜欢将任何必需的数据传递到构造函数中,因为它定义了我的类所需的依赖关系。
将xml数据传递到构造函数中的另一个问题是与传递具体类型不同。具体类型定义了一组已知的属性或字段,而xml并不保证结构...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接