这种模式叫什么?
当您在对象的构造函数中为对象提供一个参数并且该对象用该参数填充其字段时,这种模式被称为什么?
例如:
/// <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);
并且让它解析它需要的内容并填充它的字段。
感谢您的指导。
编辑:阅读了您的所有建议后,我对代码进行了一些清理。你认为这样更好吗?您会改进哪些方面?
感谢您花时间提供帮助,我正在努力改掉不良的编程习惯。
What is this pattern called, when you give an object a parameter in its constructor and the object populates it's fields with the parameter?
For example:
/// <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();
}
}
What would this pattern be called? Also, in an effort to make my code cleaner, do you recommend I use this pattern when creating objects within objects, like in my UserWhoPosted variable. Instead of having:
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
}
I'd have:
UserWhoPosted = new Friend(myFriendXElementVariable);
And just let it parse what it needs and populate it's fields.
Thanks for the guidance.
EDIT: After reading all your suggestions I cleaned the code up a bit. Do you think this is better? What would you improve?
Thanks for taking the time to help, I'm trying to cast aside bad programming habits.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这样做绝对违反了德米特定律:
你真的不想有这么长的方法调用链。让 Friend 从其参数中询问值是一个更好的设计,耦合性也大大降低。
子部分、朋友、访客……应该自行填充,而不是对其进行工作。这将您的担忧分开。它还使测试变得更容易,因为您可以存根顶级参数,而无需深入三层来满足构造函数。
It's definitely a a violation of the Law of Demeter to do the :
You really don't want to have such a long chain of method calls. Making the Friend ask for the values from its argument is a much better design, with a lot less coupling.
The subparts, friends, visitors, ... should populate themselves not have work done to them. This separates your concerns. It also makes testing easier as you can stub the toplevel argument without needing to go three levels deep to satisfy the constructor.
在您的示例中,我倾向于将任何所需的数据传递到构造函数中,因为它定义了我的类所需的依赖。
另一个问题是将 xml 数据传递到构造函数而不是具体类型。具体类型定义了一组已知的属性或字段,而 xml 不保证结构......
In your example, I have a preference to pass any required data into the constructor, as it defines a dependancy my class requires.
The other issue with passing xml data into a constructor as opposed to a concrete type. A concrete type defines a known set of properties or fields, where as xml doesn't guarantee structure...
对我来说,这更像是一种反模式:您在构造函数中包含 xml 请求、读取和字段初始化。
也许您可以使用像这样的工厂模式:
也许您可以添加一些单例以便能够对您的类进行单元测试。
For me it's more an anti-pattern : you include xml requesting, reading, and field initialization in your constructor.
Maybe you could use a Factory pattern with like this :
Maybe you can add some singleton to be able to unit test your classes.
我想将其称为 适配器 的变体,因为您真正要做的就是包装一些XML 结构改为更加友好的类型。
I would want to call it a variation of the Adaptor , because all you are really doing is wrapping some XML structure to a more friendly type.
这不是一个模式。设计模式是解决常见问题的东西,例如当值发生变化时如何使客户端保持更新(观察者)。这并不是真正的问题,这只是语言语法的问题。你的第二个问题的答案是肯定的。
It's not a pattern. A design pattern is something that solves a common problem, such as how to keep clients updated when a value changes (Observer). This isn't really a problem, it's just language syntax. And the answer is yes to your second question.
在构造函数中做如此繁重的事情是不好的做法,我建议您将构造函数设为私有并创建将返回 User 实例的静态 Load 方法。我不知道这个模式怎么称呼。
It's bad practice to do such heavy things in constructor, I suggest you to make constructor private and create static Load method that will return User's instance. I don't know how this pattern called.
好吧,这不是一种“已知模式”,但可能是您使用的一种模式(没问题……模式就是针对既定问题的常见解决方案)。
但是,由于您的用户类负责加载自身,因此我认为该类作为 DAO 工作。
正如其他用户所说,您的构造函数中有太多逻辑。构造函数应该只具有创建对象所必需的参数,并且做尽可能少的工作。构造函数最好也避免抛出异常;由于代码越多,发生异常的机会就越高,在构造函数上执行的操作越多,抛出异常的机会就越高。
现在,看看你的类......我看到你的“用户”有诸如名称,评级等字段。在用户对象的生命周期中,是否允许不填充此类字段?也许,在创建新用户时,确实如此。因此,用户拥有此 ID 并不是先决条件,根据我所说的规则,这将使构造函数无效。
尝试创建一个返回新用户的 Load 静态方法或创建一个工厂。它将在未来的可维护性等方面为您提供帮助。
最后,尝试查看 存储库模式。您可以使用它而不是普通工厂来维护您的用户和其他对象。
Well, this is not a "known pattern", could be one that you use though (no problem there... patterns are just that, common solutions to well established problems).
However, since your user class is responsible for loading itself, I'd say that the class is working as a DAO.
As other users have stated, you have too much logic in your constructor. Constructors should only have parameters that are essential to creating the object and do as little work as possible. It would be preferable that constructors avoid throwing exceptions too; Since the more code, the higher chance of an exception,the more you do on a constructor, higher the chance it throws.
Now, take a look at your class... I see that your "User" have fields such as Name, Rating, etc. Isn't it allowed, during the lifetime of an user object, for it not to have such fields filled? Probably, when creating a new user, that would be true. So it's not a pre-requisite for the user to have this ID, which would make the constructor invalid by the rule I stated.
Try making a Load static method that returns a new User or create a Factory. It will help you in the future with maintainability, etc.
Finally, try taking a look at the Repository Pattern. You could use it instead of a plain factory to maintain your User and other objects.