对象对其他对象了解多少?是违反得墨忒耳定律的例子吗?
How much can object know about other object? Is it example of demeter's law violation?
我对如何允许对象相互了解存在疑问。
在我的简单示例中,我有 classes:Bill
、Customer
、Checkout
和 Cart
。客户有他们的 bills
列表,购物车与 customer
相关联并且结帐完成购买操作(将 bill
添加到 customer
)
SO 在方法 public void checkouts(Cart cart)
中初始化新账单 Bill bill = new Bill(cart)
然后我想向客户添加账单。我有 3 种可能的方法:
cart.getCustomer().getBills().add(bill);
// ^^^ directly add bill to ArrayList in Customer
cart.getCustomer().addBill(bill);
// ^^^ Customer get bill and put it itself in their own method
cart.addBillToCustomer(bill);
// ^^^ In this example class Checkout doesn't now anything about customer.
// Responsibility goes to cart which calls getCustomer().addBill(bill)
我猜第一个真的是错误的,因为 Checkout
必须知道 getBills()
returns array list
(这很危险)
在第二个示例中 class checkouts
获取与其没有直接关联的客户,并且它必须知道客户界面才能添加账单。
在第三个结账示例中,它与客户没有直接关联,不使用任何关于客户的知识,它只是将任务委托给直接连接到 customer
的 cart
(它有现场客户客户)
哪个解决方案最好,为什么以及为什么其他解决方案更差?
三个在 Java
中有效,但最好的解决方案是 cart.addBillToCustomer(bill);
只有 如果 您在 addBillToCustomer
方法中进行必要的验证。
选项 1:cart.getCustomer().getBills().add(bill);
这样做的主要问题是您依赖于集合的可变性 getBills()
returns。这是一个坏主意,因为它破坏了封装,这就是为什么通常在 getter 中返回内部集合的不可变 copy/view 的原因。到那时,这个解决方案根本行不通。
选项 2:cart.getCustomer().addBill(bill);
这假设知道购物车将有一个与之关联的客户,并且客户可以向他们添加账单。这些假设没有错,但还有第三个隐含的假设:Cart
不需要知道客户何时收到新账单。事实上 Cart
甚至不必存在。
选项 3:cart.addBillToCustomer(bill);
从上面继续,第三次调用的语义非常不同。这个电话说的是:Customer
s 只能通过 Cart
s.
计费
结论
总而言之:选项 1 是完全错误的,但是选择选项 2 还是选项 3 取决于您希望模型表达的内容,它们代表了业务逻辑之间的实际差异。
为什么需要单独的 Bill 和 Cart 对象?看起来很奇怪,你有一个购物车,你从那里得到客户,然后给客户添加账单。
客户可能只有状态为已付款或未付款的 Cart 对象,为什么将它们分开很重要?
(我问这个是因为如果你现在可以简化抽象,以后可能会受益)
首先,让我们试着弄清楚得墨忒耳定律的内容:
Law of Demeter (LoD):
A method f of a class C should only call the
methods of these:
- C
- An object created by f
- An object passed as an argument to f
- An object held in an instance variable of C
让我们考虑一些使用您的 Checkout
class:
的示例
public class Checkout {
private MyLogger logger;
public void log(String msg) {
// Write down the msg here
}
// 1. method log1 should call method(s) of class Checkout, i.e Checkout.log
public void log1() {
log("Hello");
}
// 2. method log2 should call method(s) of an object created by itself, i.e Date.toString
public void log2() {
Date now = new Date();
System.out.println(now.toString());
}
// 3. method log3 should call method(s) of an object passed as an argument to it, i.e Cart.toString
public void log3(Cart cart) {
System.out.println(cart.toString());
}
// 4. method log4 should call method(s) of an object which is an instance variable of C, i.e Logger.log
public void log4() {
logger.log("some log message");
}
public void checkouts(Cart cart) {
Bill bill = new Bill()
cart.getCustomer().getBills().add(bill);
// ^^^ directly add bill to ArrayList in Customer
cart.getCustomer().addBill(bill);
// ^^^ Customer get bill and put it itself in their own method
cart.addBillToCustomer(bill);
// ^^^ In this example class Checkout doesn't now anything about customer.
// Responsibility goes to cart which calls getCustomer().addBill(bill)
}
}
public class Cart {
Customer customer;
}
public class Customer {
List<Bill> bills;
public void addBill(Bill bill) {
}
}
public class Bill {}
现在,回到你的问题:
1.对象对其他对象了解多少?
得墨忒耳定律中有明确规定:
class C 的方法 f 应该只调用这些方法:
- C
- f创建的对象
- 作为参数传递给 f 的对象
- C 的实例变量中保存的对象。
2。是得墨忒耳违例的例子吗?
- 第一种情况和第二种情况。
- 第三种情况可以 - 一个对象 (
Cart
) 作为参数传递给 f
解释:
对于第一个cart.getCustomer().getBills().add(bill);
,如果我们改变实现如下:
public class Customer {
Bill bills[]; // error bills.add(Bill)
}
然后代码将不再有效,因为数组没有 add 方法。
另外,对于第二个:
cart.getCustomer().addBill(bill);
public class Customer {
Bill bills[];
public void addBillBefore (Bill bill) {
bills.add(bill);
}
必须改为
public void addBillAfter(Bill bill) {
// Assume that current index is correctly setup
bills[currentIndex] = bill
}
}
也就是说,必须更改客户的实施。
我对如何允许对象相互了解存在疑问。
在我的简单示例中,我有 classes:Bill
、Customer
、Checkout
和 Cart
。客户有他们的 bills
列表,购物车与 customer
相关联并且结帐完成购买操作(将 bill
添加到 customer
)
SO 在方法 public void checkouts(Cart cart)
中初始化新账单 Bill bill = new Bill(cart)
然后我想向客户添加账单。我有 3 种可能的方法:
cart.getCustomer().getBills().add(bill);
// ^^^ directly add bill to ArrayList in Customer
cart.getCustomer().addBill(bill);
// ^^^ Customer get bill and put it itself in their own method
cart.addBillToCustomer(bill);
// ^^^ In this example class Checkout doesn't now anything about customer.
// Responsibility goes to cart which calls getCustomer().addBill(bill)
我猜第一个真的是错误的,因为 Checkout
必须知道 getBills()
returns array list
(这很危险)
在第二个示例中 class checkouts
获取与其没有直接关联的客户,并且它必须知道客户界面才能添加账单。
在第三个结账示例中,它与客户没有直接关联,不使用任何关于客户的知识,它只是将任务委托给直接连接到 customer
的 cart
(它有现场客户客户)
哪个解决方案最好,为什么以及为什么其他解决方案更差?
三个在 Java
中有效,但最好的解决方案是 cart.addBillToCustomer(bill);
只有 如果 您在 addBillToCustomer
方法中进行必要的验证。
选项 1:cart.getCustomer().getBills().add(bill);
这样做的主要问题是您依赖于集合的可变性 getBills()
returns。这是一个坏主意,因为它破坏了封装,这就是为什么通常在 getter 中返回内部集合的不可变 copy/view 的原因。到那时,这个解决方案根本行不通。
选项 2:cart.getCustomer().addBill(bill);
这假设知道购物车将有一个与之关联的客户,并且客户可以向他们添加账单。这些假设没有错,但还有第三个隐含的假设:Cart
不需要知道客户何时收到新账单。事实上 Cart
甚至不必存在。
选项 3:cart.addBillToCustomer(bill);
从上面继续,第三次调用的语义非常不同。这个电话说的是:Customer
s 只能通过 Cart
s.
结论
总而言之:选项 1 是完全错误的,但是选择选项 2 还是选项 3 取决于您希望模型表达的内容,它们代表了业务逻辑之间的实际差异。
为什么需要单独的 Bill 和 Cart 对象?看起来很奇怪,你有一个购物车,你从那里得到客户,然后给客户添加账单。
客户可能只有状态为已付款或未付款的 Cart 对象,为什么将它们分开很重要?
(我问这个是因为如果你现在可以简化抽象,以后可能会受益)
首先,让我们试着弄清楚得墨忒耳定律的内容:
Law of Demeter (LoD):
A method f of a class C should only call the methods of these:
- C
- An object created by f
- An object passed as an argument to f
- An object held in an instance variable of C
让我们考虑一些使用您的 Checkout
class:
public class Checkout {
private MyLogger logger;
public void log(String msg) {
// Write down the msg here
}
// 1. method log1 should call method(s) of class Checkout, i.e Checkout.log
public void log1() {
log("Hello");
}
// 2. method log2 should call method(s) of an object created by itself, i.e Date.toString
public void log2() {
Date now = new Date();
System.out.println(now.toString());
}
// 3. method log3 should call method(s) of an object passed as an argument to it, i.e Cart.toString
public void log3(Cart cart) {
System.out.println(cart.toString());
}
// 4. method log4 should call method(s) of an object which is an instance variable of C, i.e Logger.log
public void log4() {
logger.log("some log message");
}
public void checkouts(Cart cart) {
Bill bill = new Bill()
cart.getCustomer().getBills().add(bill);
// ^^^ directly add bill to ArrayList in Customer
cart.getCustomer().addBill(bill);
// ^^^ Customer get bill and put it itself in their own method
cart.addBillToCustomer(bill);
// ^^^ In this example class Checkout doesn't now anything about customer.
// Responsibility goes to cart which calls getCustomer().addBill(bill)
}
}
public class Cart {
Customer customer;
}
public class Customer {
List<Bill> bills;
public void addBill(Bill bill) {
}
}
public class Bill {}
现在,回到你的问题:
1.对象对其他对象了解多少?
得墨忒耳定律中有明确规定: class C 的方法 f 应该只调用这些方法:
- C
- f创建的对象
- 作为参数传递给 f 的对象
- C 的实例变量中保存的对象。
2。是得墨忒耳违例的例子吗?
- 第一种情况和第二种情况。
- 第三种情况可以 - 一个对象 (
Cart
) 作为参数传递给 f
解释:
对于第一个cart.getCustomer().getBills().add(bill);
,如果我们改变实现如下:
public class Customer {
Bill bills[]; // error bills.add(Bill)
}
然后代码将不再有效,因为数组没有 add 方法。
另外,对于第二个:
cart.getCustomer().addBill(bill);
public class Customer {
Bill bills[];
public void addBillBefore (Bill bill) {
bills.add(bill);
}
必须改为
public void addBillAfter(Bill bill) {
// Assume that current index is correctly setup
bills[currentIndex] = bill
}
}
也就是说,必须更改客户的实施。