问题 我打破了“得墨忒耳法则”吗?


我最近才意识到这一点 得墨忒耳定律

像很多事情一样,我意识到这是我已经在做的事情,但却没有名字。虽然有几个地方我似乎违反了它。

例如...

我可能有一个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一段时间。


10616
2017-09-14 06:05


起源

那些C ++人少数呢? ( - Kornel Kisielewicz
对不起Kornel。我的意思是没有不尊重。帖子变得很长。我可以用一百万种语言作为例子。 Java家伙似乎喜欢他们的模式,我认为值得添加一个片段,如果它会有所帮助。对我的问题的任何见解? - Justin
看到 haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx - Ian Mercer
@Hightechrider - 为什么不发帖作为答案?我可能会接受它。 - Justin
我打破了“得墨忒耳法则”吗?更新城市地址而不更新其他东西是否有意义? - CurtainDog


答案:


本文: http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx 对您正在讨论的问题有一个很好的解释。

正如他所指出的那样,这不是一个点数计算练习,而是一个耦合问题。目前你的 Customer 和 Address 类太紧密耦合了。对于初学者, Customer 不应该制作新的地址,也许不会通过 Address 在使用构造函数。至于你是否应该使用多个点来访问地址的一部分,请阅读文章......

Martin Fowler:“我更喜欢将其称为Demeter的偶尔有用的建议。”


11
2017-09-14 07:34



Uuuh,我喜欢那句话:D - atamanroman
感谢您将此作为答案发布。报价很好地总结了这篇文章。 - Justin


违反了得墨忒耳法则是指代码气味的实例 不恰当的亲密关系。要消除这种气味,您可以通过隐藏地址的内部并在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
2017-09-14 06:23



如果您的地址实施发生变化,它也有好处,您只需维护一个类。 - InsertNickHere
实际上,这种不恰当的亲密关系的主要问题不在于Customer类本身。它在使用Customer的类中。任何可以访问客户持有的对象的类都对Customer有太多了解。此外,客户和地址似乎是某种贫血阶层,只是数据集团。 - Stephan


这里的问题是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);
    }
}

1
2017-11-18 22:12