设计模式逐步“填充”一个物体(初学者问题)
我需要处理一堆数据 - 每个元素(数据?)本质上只是文本属性的字典。假设该类是书籍 - 它可能有作者、标题、类型、阅读难度级别和建议价格。现在,我开始只知道前两本,对于每本书,需要推断或估计接下来的三本(在我的问题中,它不止于此)。
因此,对我来说很自然的方法是对每本书迭代地执行此操作。我的设计看起来类似于(这是用 Java 编写的)
public class Book
{
public String author;
public String title;
/* ... */
public double price;
public Book(String author,String title)
{
this.author = author;
this.title = title;
}
public void setGenre(DataProvider dp,...)
{
/* some sort of guess, resulting in genreGuess */
this.genre = genreGuess;
}
/* .. and so on for price, etc */
}
然后,我的代码会喜欢:
for (Book book : bookList)
{
setGenre(book);
setPrice(book);
/* and so on */
}
但是,我正在尝试学习如何以较少迭代的方式、使用较少可变状态更好地设计程序。有人对我如何解决这个问题有任何建议吗?
I need to process a bunch of data - each element (datum?) is essentially just a dictionary of textual attributes. So say the class is Book - it might have an author, title, genre, reading difficulty level, and recommended price. Now, I start off only knowing the first two, and for each book, need to infer or estimate the next three (in my problem it is more than that).
So the approach that is natural to me is to do this iteratively for each book. My design would look something along the lines of (this is in Java)
public class Book
{
public String author;
public String title;
/* ... */
public double price;
public Book(String author,String title)
{
this.author = author;
this.title = title;
}
public void setGenre(DataProvider dp,...)
{
/* some sort of guess, resulting in genreGuess */
this.genre = genreGuess;
}
/* .. and so on for price, etc */
}
And then, my code would like:
for (Book book : bookList)
{
setGenre(book);
setPrice(book);
/* and so on */
}
However, I am trying to learn how to design programs better, in a less iterative fashion, using less mutable state. Does anyone have any recommendations on how I might go about this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不是面向对象设计大师...这是我个人认为更好的一种方法。
将 GenreGuesser 接口的实现注入到 Book 中...这最好通过 BookFactory 来完成。工厂配置一次,然后用于创建“类似”的书籍。我正在考虑在这里使用依赖注入(如 Springs DI 框架或 Google 的 Guice),这极大地减少了将工厂“连接”到依赖于它们的事物的开销;-)
然后我们可以检索并缓存即时计算属性。请注意,缓存结果意味着图书对象身份(例如:作者和标题)是最终的,或者至少是固定一次设置的。
因此基本上您正在为每个计算字段执行自己的“后期绑定”。如果默认的“猜测”不准确,也没有什么可以阻止您(或用户)手动设置每个字段。
这在 Book 类上实现了一个简单的“丰富”接口;以让 Book 意识到“猜测”这个概念为代价……而我本身并不喜欢“智能”转移对象,这让我想起了另一种方法。
如果我们要接受 BookFactory 类的所有开销,并且我们可以限制自己只能通过工厂创建书籍,那么为什么不直接让 BookFactory (根据定义,它知道有关 Book 及其属性的所有信息)使用(猜测的)默认值填充所有计算字段。然后 Book 类又回到了一个简单、愚蠢的传输对象,它完全完成了它所需要的工作,除此之外什么也不做。
我有兴趣阅读其他人的建议。
干杯。基思.
I'm NOT an OO-design guru... Here's one way which I personally think is better.
Inject an implementation of the GenreGuesser interface into Book... this is best done via a BookFactory. The factory is configured ONCE, and then used to create "like" books. I'm thinking of using dependency injection here (like Springs DI framework, or Google's Guice), which dramatically cut-down the overhead of "wiring" the factories into the things which depend on them ;-)
Then we could retrieve AND CACHE the calculated attribute on-the fly. Note that caching the result implies that a Book-objects IDENTITY (eg: author & title) are final, or atleast fixed-once-set.
So basically you're doing your own "late binding" for each calculated field. There's also nothing stopping you (or the user) from setting each field manually if the default "guess" is off-base.
This achives a simple "rich" interface on the Book class; at the cost of making Book aware of the concept "guesses"... and I'm not a fan of "intelligent" transfer-objects, per se, which brings to mind another approach.
If we're going to accept all the overhead of having a BookFactory class, and we CAN limit ourselves to ONLY EVER creating books through the factory, then why not just let the BookFactory (which by definition knows all-about Book and it's attributes) populate all the calculated fields with (guessed) default values. Then the Book class is back to being a simple, dumb, transfer object, which does exactly what it needs to, AND NOTHING ELSE.
I'll be interested to read others suggestions.
Cheers. Keith.
这里的关键是您所描述的类是一个非常简单的类,因此很难看出如何改进它。
然而,在实际系统中发生的情况是,您的 Author 类将是与 Person 和 Contract 的连接,或者 Book 将有一个 Publisher。在图书馆中,它可能有购买时间、借出和归还时间的历史记录,以及 ISBN 和国会图书馆记录之类的信息。
对象背后将是某种持久存储——从简单的Python“pickling”到关系数据库或“NoSQL”表存储。
这就是复杂性开始显现的地方。
因此,这里有一些需要考虑的事情:
您打算存储多少个对象? 10 本书的决策与存储 1000 万本书所需的决策有很大不同。
如果您有一个复杂的对象树 - 包含出版商、作者、人员、合同、LC 记录、库存等 - 那么从 .persistent 存储创建(或“补充”)对象可能需要很长时间。当面向对象刚开始流行时,这是森林系统中的一个传统问题:对象模型很棒,但加载一个对象及其所有连接的对象需要半个小时。
此时,您需要开始考虑延迟评估。另一个有用的模式是 Flyweight——您无需制作许多副本,而是缓存一个副本并简单地引用它。
什么是用例?您不能只是说“我想为一本书建模”,因为您不知道这本书的用途。。从用例开始,逐步实现让类的方法能够轻松编写代码的目标。
处理这个问题的最佳方法基本上是编写代码。使用您的对象写出、草拟、实际的代码示例,看看它们是否易于使用。
正如弗雷德·布鲁克斯所说,“计划扔掉一个;无论如何你都会扔掉。”就像写散文一样,编写代码就是重写。
The key thing here is that the class you're describing is a very simple one, so it's hard to see how it could be improved.
What happens in real systems, however, is that your Author class would, for example, be a connection to a Person and a Contract, or the Book would have a Publisher. In a library, it might have a history of when it was purchased, when it was loaned out and returned, and something like ISBN and Library of Congress records.
Behind the objects would be some kind of persistent store -- from something as simple as Python's "pickling" to a relational data base or a "NoSQL" table store.
That's where the complexity starts to show up.
So here are some things to think about:
how many objects do you mean to store? Decisions for 10 Books are very different from what you need to store 10 million.
If you have a complicated tree of objects -- with Publisher, Author, Person, Contract, LC records, inventory and so on -- then creating (or "rehydrating") the object from .persistent store can take a long time. Back when OO was first catching on, this was a traditional issue in forst systems: the object model was wonderful, but it took a half-hour to load an object and all its connected objects.
At that point, you need to start thinking about lazy evaluation. Another useful pattern is Flyweight -- instead of making many copies, you cache one copy and simply refer to it.
What are the use cases? You can't just say "I want to model a Book" because you don't know what the book is for. Start with use cases, and work down to the goal of having the methods of your class make it easy to write code.
The best way to handle that is, basically, to write code. Write out, sketch, actual examples of code using your objects and see if they are easy to use.
As Fred Brooks says, "plan to throw one away; you will anyway." As in writing prose, writing code is rewriting.
我注意到的第一件事是 setGenre 和 setPrice 是 Book 对象的成员方法。在这种情况下,您不应该传递一本书,而应该打电话
但我不确定您是否应该这样做。如果您尝试从作者和标题推断类型和难度并最终推断价格,则不应显式调用 setGenre()。
相反,您可以调用
or
然后该方法可以在返回最终价格之前推断性别和难度。
Firs thing I notice is that setGenre and setPrice are member methods on the Book object. In that case, you shouldn't be passing in a book, but rather calling
But I'm not sure you should even be doing that. If you're trying to infer Genre and Difficulty and ultimately Price from the author and title, you shouldn't be explicitly calling setGenre().
Instead, you could call
or
Then that method could infer gender and difficulty before returning the final price.