长对象调用链是否有任何内在错误?

All*_*nde 6 architecture design-patterns law-of-demeter method-chaining

我已经按层次结构组织了我的代码,并发现自己使用以下代码爬上树.

File clientFolder = task.getActionPlan().getClientFile().getClient().getDocumentsFolder();
Run Code Online (Sandbox Code Playgroud)

我没有钻进这个task物体; 我正在向它的父母钻研,所以我认为我在封装方面没有失去任何东西; 但是我脑子里的一面旗帜正在告诉我这样做有什么不好的事情.

这是错的吗?

Ste*_*owe 5

国旗是红色的,它用粗体表示两件事:

  • 为了跟随链,调用代码必须知道整个树结构,这不是很好的封装,并且
  • 如果层次结构发生变化,您将需要编辑大量代码

括号中有一件事:

  • 使用属性,即task.ActionPlan而不是task.getActionPlan()

一个更好的解决方案可能是 - 假设您需要在子级别公开树上的所有父级属性 - 继续并在子级上实现直接属性,即

File clientFolder = task.DocumentsFolder;
Run Code Online (Sandbox Code Playgroud)

这至少会隐藏调用代码中的树结构.在内部,属性可能如下所示:

class Task {
    public File DocumentsFolder {
        get { return ActionPlan.DocumentsFolder; }
    }
    ...
}
class ActionPlan {
    public File DocumentsFolder {
        get { return ClientFile.DocumentsFolder: }
    }
    ...
}
class ClientFile {
    public File DocumentsFolder {
        get { return Client.DocumentsFolder; }
    }
    ...
}
class Client {
    public File DocumentsFolder {
        get { return ...; } //whatever it really is
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是如果树结构将来发生变化,您只需要更改树中涉及的类中的访问器函数,而不是每个调用链的地方.

[此外,在属性函数中正确捕获和报告空值会更容易,这在上面的示例中省略了]


Bil*_*ill 0

世界上最大的旗帜。

您无法轻松检查这些调用中的任何一个是否返回空对象,因此几乎不可能跟踪任何类型的错误!

getClientFile() 可能会返回 null,然后 getClient() 将失败,当您捕捉到这一点时,假设您正在尝试捕捉,您将不知道哪一个失败了。