试图理解得墨忒耳定律,因为它适用于我的代码
Trying to understand the Law of Demeter as it applies to my code
我有一个简单的Store
类,其中包含一个Inventory
。Inventory
包含Item
的列表。为了修改Inventory
中的Item
之一,我必须编写:
Store store( /*parameters*/ );
store.accessInventory(/*password*/).accessItem(/*item name*/).setPrice(9.50);
据我了解,这违反了得墨忒耳定律,因为Store
必须通过Inventory
进入Item
才能召唤setPrice()
。
我想将这种违法行为与经典例子中的违法行为与纸男孩和客户之间的违法行为相协调。在纸男孩的例子中,纸男孩"了解"了太多关于客户的信息,假设他会用钱包付款。如果客户的付款方式发生变化,纸男孩也必须改变。
在我的代码中做出了哪些假设,可能会导致像纸男孩示例中遇到的问题?
我知道法律实际上更像是一个指导方针,在这种情况下遵守它可能不是最好的主意,但我想在继续之前至少了解法律。谢谢。
您的代码假定 Inventory 对象是唯一需要在价格更改时通知的对象。
想象一下,除了包含商品清单外,您的商店还在其橱窗中挂了一些广告海报。
如果您遵循得墨忒耳定律,您的 Store 对象可能有一个不错的方法,如下所示:
void Store :: SetItemPrice(string item_name, float item_price)
{
inventory.SetItemPrice(item_name, item_price);
for (int i=0; i<num_advertising_posters; i++)
{
// Update any posters with the new price!
if (advertising_posters[i].advertised_item == item_name)
{
advertising_posters[i].SetAdvertisedPrice(item_price);
}
}
}
。但是,如果您允许调用代码直接访问库存对象,那么就没有简单/万无一失的方法来确保每当价格更新时广告始终得到更新,因此在某些时候,您商店的广告海报可能会显示产品的旧/错误价格。 得墨忒耳定律使避免这种错误变得更加容易。
在我的代码中做出了哪些假设,可能会导致像纸男孩示例中遇到的问题?
愤怒的客户。愤怒的工作人员。愤怒的经理。愤怒的会计师。
当列出的价格高于他们收取的价格时,客户不介意感到惊讶,但是当他们被收取的价格高于他们预期的价格时,他们肯定会被POed。工蜂不喜欢愤怒的顾客来找他们,因为愚蠢的新手商店经理不遵守协议并直接在库存中更改价格。中低层管理者也不喜欢这样,因为他们会从四面八方感到悲伤。豆类计数器也喜欢在豆子的价值突然变化时得到通知。
这不仅仅是杰里米在回答中提到的广告海报。需要告诉某人更改指定价格的物品堆旁边的小定价标签。需要派遣一群人携带便携式打印机来更改该类型每件商品上印有的价格。这些人需要安排,你最好不要在没有与部门经理交谈的情况下这样做。等等等等。通过库存来改变价格是一个坏主意。
顺便说一句,以上所有内容都来自一个认为得墨忒耳定律最好称为得墨忒耳偶尔有用的建议的人。
您的示例非常接近 paperboy 示例。您的代码依赖于具有 setPrice(float) 方法的当前 Item 接口。如果更改该接口,则需要更新
store.accessInventory(password).accessItem(name).setPrice(price)
它发生的任何地方。
更好的解决方案是为表单的商店和库存创建函数
void Store::setItemPrice(string password, string name, float price)
{
accessInventory(password).setItemPrice(name, price);
}
无效库存::设置项目价格(字符串名称,浮动价格)
{ accessItem(name).setPrice(price);
}
这样,您可以在代码的其余部分使用这些函数,并在物品或物品栏接口发生更改时相应地更改它们。
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- "string.h"在构建适用于iOS的qt应用程序中找不到消息
- 适用于 WebView2 旧版本的示例应用程序
- 在 NVIDIA GEFORCE GTX 1050 上下载适用于 Windows 10 的 openCL 1.2
- __attribute__(优化(0))) 是否适用于"recursively"?
- 为什么 std::erase(std::erase_if) 不是适用于<algorithm>任何容器的模板?
- 使用一个参数的模板函数时出错(适用于 2)
- 使用 适用于 Android 和 iOS 的 tf-lite C++ API
- 为什么这适用于 G++ 而不是 CLANG?
- 适用于 macOS 的 Xcode 应用程序。这就是我设置从USB麦克风输入获取音频的方式。一年前工作,现在没有了。为什么
- 适用于 Linux 的 c++ 上的代理脚本
- 为什么我的 SFINAE 表达式不再适用于 GCC 8.2?
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 有没有适用于Windows.lib文件的GNU二进制文件描述符(BFD)
- 模板函数仅适用于VS
- 如何在cmake中包含适用于g++或viceversa的库
- 适用于win32、linux、mac的POSIX C包装器
- WinDBG适用于从Visual Studio 2015保存的转储,但不适用于任务管理器。显示异常代码"not found"
- 从uint8_t到NPY_UINT16 PyArray_SimpleNewFromData.适用于Linux,但不适用于