我最近才意识到Law of Demeter。
像许多事情一样,我意识到这是我已经在做的事情,但却没有名字。虽然有几个地方我似乎违反了它。
例如......
我可能有一个Address对象:
public class Address : IAddress
{
public string StreetAddress { get; set; }
public string City { get; set; }
public int Zip { get; set; }
}
和一个Customer对象:
public class Customer : ICustomer
{
private IAddress address;
Customer()
{
Address = null;
}
public string Name { get; set; }
public IAddress
{
get
{
if (address == null)
{
address = new Address();
}
return address;
}
set
{
address = value;
}
}
}
好的,这是假代码所以你可能不必跳我使用IoC来消除new Address()
或其他什么,但它几乎就是我正在做的事情的一个例子。我没有包含接口,因为我希望它们是显而易见的。
然后我会在代码中使用它来处理int zip = customer.Address.Zip;
和customer.Address.City = "Vancouver";
据我了解,我通过操纵客户地址的详细信息违反了得墨忒耳法。
然后,似乎框架也是如此。毕竟,不会解决.City.Length是违规?我应该在Address中添加方法来处理访问字符串属性吗?可能不是。那么,为什么地址混乱?
我真的不能只添加仅与客户相关的Address方法。我有会员,员工,受抚养人,供应商,雇主等等都有地址的对象。
有没有更好的方法来解决这个问题?如果我按照现在的方式使用Address,我会冒什么样的问题?
对于Java人员,如果有帮助,则Address类可能看起来更像下面的内容:
public class Address extends AddressInterface
{
private String m_city;
public String getCity() { return m_city; }
public void setCity(String city) { m_city = city; }
}
我必须承认customer.getAddress().setCity("Vancouver");
发出的警报比customer.Address.City = "Vancouver";
给我的警报多。也许我应该转用Java一段时间。
答案 0 :(得分:11)
这篇文章:http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx对您正在讨论的问题有很好的解释。
正如他所指出的那样,这不是一个点数计算练习,而是一个耦合问题。目前,您的Customer
和Address
类过于紧密。对于初学者,Customer
不应该创建新地址,也许使用构造函数传递Address
。至于你是否应该使用多个点来访问地址的一部分,请阅读文章......
Martin Fowler:“我更喜欢将其称为Demeter的偶尔有用的建议。”
答案 1 :(得分:2)
违反Demeter法则是名为 Inappropriate Intimacy 的代码气味的实例。要消除这种气味,您可以通过隐藏地址的内部并在Customer中委托地址实现方法来重构代码。这样,您就会尊重Customer内部地址的封装。
示例:
public class Customer extends ICustomer{
private Address address;
....
public void setCity(String city){
address.setCity(city);
}
public String getCity(){
return address.getCity();
}
}
希望这有帮助。
答案 2 :(得分:1)
这里的问题是Address是一个ValueObject。如果不改变拉链,你永远不会改变城市。
public class Customer extends ICustomer{
private Address address;
....
public void setAddress(String street, String city, int zip){
address = Address.new(street, city, zip);
}
// or even better but i'm not sure if it's valid C#
public void setAddress(int zip){
address = Address.lookup(zip);
}
}