Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 德米特定律和构图与收藏品是如何协同工作的?_Java_Oop_Law Of Demeter - Fatal编程技术网

Java 德米特定律和构图与收藏品是如何协同工作的?

Java 德米特定律和构图与收藏品是如何协同工作的?,java,oop,law-of-demeter,Java,Oop,Law Of Demeter,我已经阅读了几乎所有的题为德墨忒尔定律的问题。我的具体问题在其他任何问题中都没有得到回答,尽管它非常相似。我的主要问题是,当您有一个具有组成层的对象,但需要从各种对象检索属性值时,如何实现这一点,以及为什么要采用一种方法而不是另一种方法 假设您有一个由其他对象组成的非常标准的对象,如下所示: public class Customer { private String name; private ContactInfo primaryAddress; private ContactI

我已经阅读了几乎所有的题为德墨忒尔定律的问题。我的具体问题在其他任何问题中都没有得到回答,尽管它非常相似。我的主要问题是,当您有一个具有组成层的对象,但需要从各种对象检索属性值时,如何实现这一点,以及为什么要采用一种方法而不是另一种方法

假设您有一个由其他对象组成的非常标准的对象,如下所示:

public class Customer {
  private String name;
  private ContactInfo primaryAddress;
  private ContactInfo workAddress;
  private Interests hobbies;
  //Etc...

  public getPrimaryAddress() { return primaryAddress; }
  public getWorkAddress() { return workAddress; }
  public getHobbies() { return hobbies; }
  //Etc...
}

private ContactInfo {
  private String phoneNumber;
  private String emailAddress;
  //Etc...

  public getPhoneNumber() { return phoneNumber; }
  public getEmailAddress() { return emailAddress; }
  //Etc...
}

private Interests {
  private List listOfInterests;
}
以下两项都将违反德米特法:

System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber());
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString());
我认为这也违反了德米特法(澄清?):

因此,您可能会向Customer添加一个“getPrimaryPhoneNumber()”方法:

public getPrimaryPhoneNumber() {
  return primaryAddress.getPhoneNumber();
}
然后简单地打电话: System.out.println(“电话:+customer.getPrimaryPhoneNumber())

但随着时间的推移,这样做似乎会带来很多问题,并违背了德米特法的意图。它将Customer类变成了一个巨大的getter和setter包,这些getter和setter对其内部类有太多的了解。例如,客户对象可能有一天会有不同的地址(不仅仅是“主”和“工作”地址)。也许甚至Customer类也只是拥有ContactInfo对象的列表(或其他集合),而不是特定的命名ContactInfo对象。在这种情况下,你如何继续遵循德米特定律?这似乎违背了抽象的目的。例如,在客户拥有ContactInfo项目列表的情况下,这似乎是合理的:

Customer.getSomeParticularAddress(addressType).getPhoneNumber();
当你想到有些人有一部手机和一部固定电话,然后ContactInfo必须有一组电话号码时,这似乎会变得更疯狂

Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
在这种情况下,我们不仅要在对象中的对象中引用对象,还要知道有效的addressType和phoneType是什么。我可以肯定地看到这是一个问题,但我不知道如何避免它。特别是当任何一个班级打电话时,他们可能都知道他们想把“移动”电话号码拨到客户的“主要”地址


如何对其进行重构以符合Demeter定律?为什么这样做很好?

根据我的经验,所示的
客户
示例不是“由其他对象组成的标准对象”,因为该示例采用了将其组成部分实现为内部类的附加步骤,并进一步将这些内部阶级私有化。这不是一件坏事

一般来说,私有访问修改器增加了信息隐藏,这是Demeter法的基础。揭露私人阶级是自相矛盾的。NetBeans IDE实际上包含一个默认编译器警告,“通过公共API导出非公共类型”

我认为,将私有类暴露在其封闭类之外总是不好的:它减少了信息隐藏并违反了Demeter定律。因此,要回答有关在
Customer
之外返回
ContactInfo
实例的澄清问题:是的,这是一种违反

Customer
添加
getPrimaryPhoneNumber()
方法的建议解决方案是一个有效的选项。困惑就在这里:“客户……对自己的内部类了解太多了。”这是不可能的;这就是为什么这个例子不是一个标准的合成例子很重要

封闭类100%了解任何嵌套类。总是。无论这些嵌套类如何在封闭类(或其他任何地方)中使用。这就是为什么封闭类可以直接访问其嵌套类的私有字段和方法:封闭类本质上知道它们的一切,因为它们是在它内部实现的

给出了一个荒谬的例子:一个类Foo,它有一个嵌套的类Bar,它有一个嵌套的类Baz,它有一个嵌套的类Qux,Foo(内部)调用Bar.Baz.Qux.method()不会违反Demeter。富已经知道了所有关于酒吧、巴兹和曲棍球的知识;因为他们的代码在Foo中,所以没有额外的知识通过长方法链传递

然后,根据德米特定律,解决方案是
Customer
不返回中间对象,无论其内部实现如何;i、 e.
Customer
是否使用多个嵌套类实现,它应该只返回其客户机类最终需要的内容

例如,最后一个代码段可能被重构为,
customer.getPhoneNumber(地址类型,电话类型)

或者如果只有少量的选择,
customer.getPrimaryMobilePhoneNumber()


这两种方法都会导致
Customer
类的用户不知道其内部实现,并确保这些用户不必通过他们不直接感兴趣的对象进行调用。

制作另一个名为
CustomerInformationProvider
的类怎么样。您可以将
Customer
对象作为构造函数参数传递给他的新类。然后你可以在这个类中写下获取电话、地址等的所有具体方法,同时保持
客户
类的整洁。

重要的是要记住,德米特定律是一个指南,而不是一个实际的法律。我们需要在稍微更深的层次上检查它的目的,以确定在这里做什么是正确的

德米特定律的目的是防止外部物体接触到另一物体的内部。访问内部有两个问题:1)它提供了太多关于对象内部结构的信息,2)它还允许外部访问
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
int nameLength = myObject.getName().length()
mylist.get(0).doSomething();
public class Customer {
    private class InternalContactInfo {
        public ContactInfo createContactinfo() {
            //creates a ContactInfo based on its own values...
        }
        //Etc....
    }
   private String name;
   private InternalContactInfo primaryAddress;
   //Etc...

   public Contactinfo getPrimaryAddress() { 
      // copies the info from InternalContactInfo to a new object
      return primaryAddress.createContactInfo();
   }
   //Etc...
}

public class ContactInfo {
   // Not modifiable
   private String phoneNumber;
   private String emailAddress;
   //Etc...

   public getPhoneNumber() { return phoneNumber; }
   public getEmailAddress() { return emailAddress; }
   //Etc...
}