代码之家  ›  专栏  ›  技术社区  ›  Justin

我是不是违反了“得墨忒尔定律”?

  •  11
  • Justin  · 技术社区  · 14 年前

    我最近才意识到 Law of Demeter

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

    我可能有一个地址对象:

    public class Address : IAddress
    {
       public string StreetAddress { get; set; }
       public string City { get; set; }
       public int Zip { get; set; }
    }
    

    以及客户对象:

    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;
          }
       }
    }
    

    new Address() 或者别的什么,但这几乎是我正在做的一个例子。我没有包括接口,因为我希望他们是显而易见的。

    然后我会在代码中使用它 int zip = customer.Address.Zip; customer.Address.City = "Vancouver";

    我真的不能仅仅添加只与客户相关的方法来解决问题。我有成员,雇员,家属,供应商,雇主等对象,都有地址。

    有没有更好的方法来处理这个问题?如果我用现在的方式来解决问题,我会冒什么样的风险?

    对于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"); 发出的警报多于 客户地址城市=“温哥华”;

    3 回复  |  直到 14 年前
        1
  •  11
  •   Mark Seemann    5 年前

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

    正如他指出的,这不是一个点计数练习,而是一个耦合问题。目前您的 Customer Address 类的耦合太紧密。首先, 客户 不应该再写新地址了,也许会通过一个 地址 在使用构造函数时。至于你是否应该使用多个点来访问地址的一部分,请阅读这篇文章。。。

    马丁·福勒:“ I'd prefer it to be called the Occasionally Useful Suggestion of Demeter. "

        2
  •  2
  •   Stephan    14 年前

    违反德墨忒尔法的是一种代号为 不恰当的亲密关系 . 为了消除这种气味,可以通过隐藏address的内部结构和在Customer中实现委托给address的方法来重构代码。这样,您就尊重了客户内部地址的封装。

    public class Customer extends ICustomer{
        private Address address;
        ....
    
        public void setCity(String city){
            address.setCity(city);
        }
    
        public String getCity(){
            return address.getCity();
        }
    }
    

    希望这有帮助。

        3
  •  1
  •   Petrik de Heus    14 年前

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