设计问题 - OO 食品应用
假设我有许多用户控件,每个用户控件位于一个窗口内的 tabitem 内。
例如,假设这是一个食物收集应用程序。然后我们有“水果”、“蔬菜”和“零食”选项卡。每个选项卡都会显示该主题的食物列表,并允许用户添加、删除、修改每个部分中的食物。食物存储在单独的文本文件中,即 Fruit.txt、Vegetable.txt、Snack.txt
实际的文本文件可能看起来像这样 (vegetable.txt):
Name Carbs Fat
Eggplant 2 1.1
Cucumber 3 0.5
etc
现在这是一个很大的列表,并且有一个加载方法可以提取所有内容 。
我的问题是这个 loadVegetables 方法位于文件后面的代码中,我最终在整个地方重复这个加载方法,因为我还有另一个其他屏幕,如 ReviewAllFood、AddVegetable 等 水果和零食的所有其他加载方法。
这更多的是一个设计问题,我想知道如何设置它以不重复此代码。我可以有一个 VegetableManager (或其他)类,其中包含加载方法,但这实际上意味着更少的重复代码吗?然后在每个屏幕中我必须创建 VegetableManager 对象并调用其加载方法。所以我认为效率方面并没有更好,但我确实实现了更好的设计。
我想我在这里遗漏了一些东西。自从我研究内聚和耦合以来已经有一段时间了,我想我现在对这些概念感到困惑。如果有人可以针对这种情况提出设计建议并解释他们为什么选择它以及为什么它比我目前的做法更好,我将不胜感激。
感谢您的阅读。
Say I have a number of usercontrols, each usercontrol inside a tabitem, inside a window.
For example, let say this is a food collection application. Then we have tabs Fruit, Vegetables and Snacks. Each tab will show a list of food of that subject, and allow the user to add, delete, modify the food in each section. The food is stored in seperate textfiles, i.e. Fruit.txt, Vegetable.txt, Snack.txt
The actual text files might look something like this (vegetable.txt):
Name Carbs Fat
Eggplant 2 1.1
Cucumber 3 0.5
etc
Now this is a large list and there is a load method which pulls all the vegetables out into a List
The question I have is this loadVegetables method is in the code behind file, and I end up repeating this load method all over the place, because I have another of other screens like ReviewAllFood, AddVegetable, etc. along with all the other load methods for fruit and snacks.
This is more of a design question, I'm wondering how I set this up to not repeat this code. I could have a VegetableManager (or something) class where the load method is, but does this actually mean less repeated code? Then in each screen I have to create object of VegetableManager and call its load method anyway. So I guess efficiency wise its no better, but I do achieve a better design.
I think I'm missing something here. It's been a while since I studied cohesion and coupling and I think i'm confusing myself with these concepts at the moment. Appreciate if someone could suggest a design for this situation and explain why they chose it and why its better than how i'm doing it at the moment.
Thanks for reading.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这样做的目的不是效率(即性能)。关键是将数据加载到单个独立对象中的细节封装起来。例如,假设您的站点变得非常大,并且您决定将数据存储移动到数据库以实现可扩展性和性能。在您所描述的现有代码中,您必须遍历每个用户控件或页面并更改加载方法的逻辑。最好的情况是,这很痛苦,最坏的情况是您会错过一些内容或错误地复制粘贴。如果逻辑被封装到一个专用对象中,其唯一的责任是知道如何从某个地方加载数据,那么您只需进行一次更改。
用户控件的代码隐藏:
VegetableManager.cs:
由于
_veggies
是静态
,因此内存中只有一组蔬菜,尽管多个调用者将实例化VegetableManager
。但因为它是静态的,所以如果您有一个多线程应用程序(例如网站),您必须在所有线程之间同步对该字段的访问(因此需要锁
)。这只是良好面向对象的冰山一角。我建议仔细阅读 UncleBob 的 SOLID 原则 和 领域驱动设计 (免费电子书)。
所以,是的,您正在重复某些内容,但您重复的只是方法调用,并且可以重复。 DRY意味着减少“逻辑”代码的重复,即决策和算法;简单的方法调用不属于此范围。但是,如果您愿意,您可以将逻辑合并到基类中,从而有效地将用户控件与必须了解 VegetableManager 的情况隔离开来,尽管我认为这是面向对象的杀伤力,或者 OOO :-)
然后您的实际控件将派生来自此而不是来自 UserControl。
更新
急切加载 VegetableManager.cs:
请注意,此急切加载版本不必在构造函数中的加载代码周围进行双重检查锁定。另请注意,加载代码位于
static
构造函数中,因为此代码初始化一个static
字段(否则,您将在每次构造时将文件中的数据重新加载到相同的共享static
字段)。因为蔬菜是急切加载的,所以您不需要在 GetAll 或 Add 中加载。The point of doing this is not efficiency (i.e. performance). The point is to encapsulate the details of loading that data into a single isolated object. Say for example that your site gets really big and you decide to move the data storage to a database for scalability and performance. In the existing code as you described, you'll have to go through each user control or page and change the logic of the load method. At the best this is a pain, and at the worst you miss some or copy-paste incorrectly. If the logic is encapsulated into a dedicated object, whose only responsibility is to know how to load the data from somewhere, then you only have to make the change once.
codebehind of user control:
VegetableManager.cs:
Because
_veggies
isstatic
, there is only one collection of veggies in memory, despite the fact that multiple callers will instantiateVegetableManager
. But because it's static, if you have a multi-threaded application (e.g. a website) you must synchronize access to that field across all threads (hence thelock
s).This is the tip of the iceberg in terms of good object-orientation. I recommend perusing UncleBob's SOLID principles, and Domain-Driven Design (free e-book).
So, yes you are repeating something, but all you're repeating is a method call, and that is ok to repeat. DRY means to mitigate the duplication of "logical" code, i.e. decision-making and algorithms; simple method calls do not fall under this. However, if you want, you can consolidate logic into a base class do this, effectively isolating the user controls from having to know about VegetableManager, though I think this is object-orientation overkill, or OOO :-)
Then your actual controls would derive from this instead of from UserControl.
Update
Eager-loading VegetableManager.cs:
Notice this eager-loading version doesn't have to do double-checked locking around the load code in the constructor. Also notice that the load code is in a
static
constructor, since this code initializes astatic
field (otherwise, you'd be reloading the data from the file on every construction into the same sharedstatic
field). Because veggies are eager-loaded, you don't need to load in GetAll or Add.我建议您在阅读文件时将蔬菜(或您正在装载的任何东西)拉出一次。然后将它们存储在一些底层数据模型中。您可以将列表以及您需要的任何其他控件绑定到底层数据模型。数据加载一次,但可以通过各种视图显示它。
编辑:添加代码
编辑2:数据模型
I would suggest pulling the vegetables (or whatever it is you're loading) out once when you read the file. Then you store them in some underlying data model. You can bind the list, and whatever other controls you need to, to the underlying data model. The data gets loaded once, but various views can display it.
EDIT: Adding code
EDIT 2: Data model
我将为此使用 存储库模式。首先,创建一个包含从每个文本文件中检索对象的方法的类:
该类应该是应用程序中唯一知道食物实际上存储在文本文件中的类。
一旦您开始工作,您可能需要考虑缓存常用数据以提高性能。
I would use the repository pattern for this. As a start, create one class containing methods to retrieve the objects from each text file:
This class should be the only class in your application that is aware that foods are actually stored in text files.
Once you get that working you might want to consider caching frequently used data to improve performance.
使用上面的设计需要考虑一些事情
并且必须阅读:
面向对象编程?
There are several things you need to consider for using a design like above
and a must read:
object-oriented programming?