我理解如何让对象相互了解是个问题。
在我的简单示例中,我已经上课: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()
会返回array list
(这很危险)
在第二个示例中,类checkouts
获得的客户不会与之直接关联,而是必须知道客户界面才能添加账单。
在第三个示例结帐中,不与客户直接关联,不要使用任何有关客户的知识,只需将任务委派给与cart
直接相关的customer
(它有现场客户客户)
哪种解决方案最好,为什么以及为什么其他人更糟?
答案 0 :(得分:3)
cart.getCustomer().getBills().add(bill);
这个问题的主要问题在于您依赖于集合getBills()
的可变性返回。这是一个坏主意,因为它破坏了封装,这就是为什么通常在getter中返回内部集合的不可变副本/视图。在那时,这个解决方案根本不会起作用。
cart.getCustomer().addBill(bill);
这假设知道购物车将有与之相关联的客户,并且客户可以添加账单。这些假设没有错,但还有第三个隐含的假设: Cart
不需要知道客户何时获得新账单。事实上Cart
甚至不存在。
cart.addBillToCustomer(bill);
继续以上,第三次调用的语义非常不同。这个电话的内容是: Customer
只能通过Cart
s 付费。
总结一下:选项1是完全错误的,但是你选择2还是3取决于你希望你的模型表达什么,它们代表了业务逻辑之间的实际差异。
答案 1 :(得分:2)
得墨忒耳定律(LoD):
C类的方法f应该只调用 方法:
- C
- 由f
创建的对象- 作为参数传递给f
的对象- 保存在C
的实例变量中的对象 醇>
让我们考虑使用您的Checkout
类的一些示例:
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。对象能了解多少其他对象?
demeter的法律明确规定: C类的方法f应该只调用这些方法:
<强> 2。这是demeter法律违法的例子吗?
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
}
}
即,必须更改客户的实施。
答案 2 :(得分:0)
三个在Java
中有效,但最佳解决方案是cart.addBillToCustomer(bill);
仅 IF 您在addBillToCustomer
方法中进行了必要的验证。
答案 3 :(得分:0)
为什么需要单独的Bill and Cart对象?你有一个购物车看起来很奇怪,你从中获得了客户并向客户添加账单。
客户可能只有国家付费或未付款的购物车对象,为什么将它们分开很重要?
(我问这个问题,因为如果你现在可以简化抽象,那么以后就可以受益了)