1

在构建表示某些对象状态的列表时,我应该询问每个对象的状态并自己修改列表,还是应该给对象列表并告诉它添加自己?

我正在为页面上的输出构建一个模板列表。表单元素要求将此列表精简为键/值对。一位同事提到我应该更多地关注“告诉,不要问”,我正在努力理解这个问题的原则。

我采取了一种方法,我创建了一个 TemplateList 实例,然后要求每个模板将自己添加到列表中。这允许模板确定它将传递给哪些参数TemplateList::addTemplate()

class TemplateList {
    public $templates = array();

    public function addTemplate($id, $label) {
        $this->templates[$id] = $label;
    }

    public function getTemplates() {
        return $templates;
    }
}

interface TemplateInterface {
    public function addToTemplateList(&$templatelist);
}

class DiskTemplate implements TemplateInterface {
    public function addToTemplateList(&$template_list) {
        $template_list->addTemplate($this->name, $this->name);
    }
}

class DatabaseTemplate implements TemplateInterface {
    public function addToTemplateList(&$template_list) {
        $template_list->addTemplate($this->id, $this->name);
    }
}

示例用法:

$template_list = new TemplateList;

// fetch $disk_templates and $db_templates

foreach ($disk_templates as $template) {
    $template->addToTemplateList($template_list);
}

foreach ($db_templates as $template) {
    $template->addToTemplateList($template_list);
}

另一种方法是询问模板的状态并将结果添加到模板列表中:

$template_list = new TemplateList;

// fetch $template

$template_list->addTemplate($template->propertiesForTemplateList());

这两种方法都有优势吗?还有什么我完全没有考虑到的吗?

4

1 回答 1

1

首先,原则上有一个小错误:它的“告诉,不要问”:)。您可以在此处找到有关此原则和其他原则的非常好的文章. 基本思想是,与其向对象提问然后决定做什么,不如告诉对象该做什么。每个对象(例如基于其内部状态)应该知道如何处理任务(消息发送)。这对于保持责任的合理分配很重要。如果你向一个对象询问某事,但决定在另一个对象上做什么,那么你就是在将一个对象的内在逻辑传播到多个对象中。这会产生难以测试和维护的代码,因为您没有内聚的对象和一个修改/测试功能的地方。这里出现的第二个问题是封装;在大多数情况下,对象的状态是私有的,人们将其公开,以便可以查询对象的状态,以便稍后执行操作。作为一般的经验法则,我认为这是一种气味,因为您(再次)不仅将对象责任分散到系统的其余部分,而且还违反了对象的封装。请注意,我在这里并不是说吸气剂本身不好,只是如果您需要公开您的状态以便其他对象可以为您做出决定,那么您可能会走错路。

现在,转到您的代码,我认为第一种方法是完全有效的,因为它是知道如何将自己添加到列表以及应该使用哪些属性的对象。您正在妥善分配职责,并在必要时封装内部状态。

高温高压

于 2012-11-12T15:25:41.630 回答