我有一个包含Store
的简单Inventory
类。 Inventory
包含Item
的列表。要修改Item
中的Inventory
之一,我必须写一下:
Store store( /*parameters*/ );
store.accessInventory(/*password*/).accessItem(/*item name*/).setPrice(9.50);
根据我的理解,这会打破Law of Demeter因为Store
必须通过Inventory
进入Item
才能调用setPrice()
。
我想将这种违法行为与纸质男孩和顾客在经典案例中违反法律相协调。在纸质男孩的例子中,纸质男孩通过假设他将用钱包付款来“了解”客户。如果客户的付款方式发生变化,纸质男孩也必须改变。
我的代码中有哪些假设可能导致问题,例如纸质男孩示例中遇到的问题?
我理解法律实际上更像是一个指导原则,在这种情况下遵守它可能不是最好的主意,但我想在继续之前至少理解法律。感谢。
答案 0 :(得分:4)
您的代码假设Inventory对象是价格变化时唯一需要通知的对象。
想象一下,除了包含商品库存外,您的商店还在其窗口中挂了一些广告海报。
如果您遵循Demeter法则,您的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);
}
}
}
...但是如果您改为允许调用代码直接访问清单对象,那么就没有简单/万无一失的方法来确保每当价格更新时广告总是会更新,所以很可能在某些情况下指出您商店的广告海报将显示产品的旧/错价格。 Demeter法则可以更容易地避免这种错误。
答案 1 :(得分:1)
你的例子非常接近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);
}
void Inventory :: setItemPrice(字符串名称,浮动价格)
{
accessItem(名称).setPrice(价);
}
通过这种方式,您可以在代码的其余部分中使用这些函数,只需在Item或Inventory接口发生更改时相应地更改它们。
答案 2 :(得分:1)
我的代码中有哪些假设会导致类似纸质男孩示例中遇到的问题?
愤怒的顾客。愤怒的人员。愤怒的经理。愤怒的会计师。
当列出的价格高于他们收取的价格时,客户不介意感到惊讶,但当他们收取的价格高于他们预期的价格时,他们肯定会得到POed。当愤怒的顾客来到他们面前时,工蜂不喜欢它,因为愚蠢的新手店经理不遵守协议并直接在库存中改变价格。中低层管理人员不喜欢这样,因为他们从各方面都感到悲痛。当豆子的价值突然改变时,Bean计数器也会被告知。
这不仅仅是杰里米在答案中提到的广告海报。需要告诉某人更改指定价格的商品堆栈旁边的小定价标签。需要使用便携式打印机派遣一群人来改变该类型的每个项目上标记的价格。这些人需要安排,如果不与部门经理交谈,最好不要这样做。等等等等。通过库存来改变价格是一个糟糕的坏主意。
顺便说一下,上述所有内容都来自于一个认为得墨忒耳法更好地称为得墨忒耳偶尔有用建议的人。