【问题标题】:Am I breaking the "Law of Demeter"?我是否违反了“得墨忒耳法则”?
【发布时间】:2011-04-12 00:16:09
【问题描述】:

我最近才知道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;
      }
   }
}

好的,这是假代码,所以你可能不必跳到我身上来使用 IoC 来消除 new Address() 或任何东西,但这几乎是我正在做的一个例子。我没有包括接口,因为我希望它们是显而易见的。

然后我会在我的代码中使用它来处理 int zip = customer.Address.Zip;customer.Address.City = "Vancouver"; 之类的东西

据我了解,我通过操纵客户地址的详细信息违反了得墨忒耳定律。

再一次,框架似乎也是如此。毕竟,address.City.Length 不是违规行为吗?我应该向地址添加方法来处理访问字符串属性吗?可能不是。那么,为什么要把地址弄得乱七八糟呢?

我真的不能只向地址添加仅与客户相关的方法。我有 Member、Employee、Dependent、Vendor、Employer 等对象,它们也都有地址。

有没有更好的方法来处理这个问题?如果我现在这样使用 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 一段时间。

【问题讨论】:

  • C++ 的少数人呢? ;(
  • 对不起Kornel。我没有不尊重的意思。帖子变得很长。我可以使用一百万种语言作为示例。不过,Java 人似乎很喜欢他们的模式,我认为如果有帮助的话,添加一个 sn-p 是值得的。对我的问题有任何见解吗?
  • @Hightechrider - 为什么不作为答案发布?我可能会接受。
  • 我是否违反了“得墨忒耳法则”?更新地址中的城市而不更新其他内容是否有意义?

标签: oop refactoring object


【解决方案1】:

这篇文章:http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx 很好地解释了您正在讨论的问题。

正如他所说,这不是点计数练习,而是耦合问题。目前你的CustomerAddress 类耦合太紧密了。对于初学者,Customer 不应该创建新地址,也许使用构造函数传递 Address。至于您是否应该使用多个点来访问地址的一部分,请阅读文章...

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

【讨论】:

  • 呃,我喜欢那句话:D
  • 感谢您将此作为答案发布。引用很好地总结了这篇文章。
【解决方案2】:

违反得墨忒耳法则是一种名为不适当的亲密关系的代码气味的实例。要消除这种气味,您可以通过隐藏地址的内部结构并在 Customer 中实现委托给地址的方法来重构代码。这样,您尊重客户内部地址的封装。

例子:

public class Customer extends ICustomer{
    private Address address;
    ....

    public void setCity(String city){
        address.setCity(city);
    }

    public String getCity(){
        return address.getCity();
    }
}

希望这会有所帮助。

【讨论】:

  • 如果你的地址实现发生变化,它也有好处,你只需要维护一个类。
  • 实际上,这种不恰当的亲密关系的主要问题不在于 Customer 类本身。它在使用 Customer 的类中。任何可以访问客户持有的对象的类都非常了解客户。此外,似乎 Customer 和 address 是某种贫乏的类,仅仅是数据块。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 2011-03-28
    相关资源
    最近更新 更多