在构建表示某些对象状态的列表时,我应该问每个对象 对象为其状态并自己修改列表,或者我应该给对象 列表并告诉它自己添加?
我正在为页面上的输出构建模板列表。表单元素 要求将此列表提炼为键/值对。一位同事提到 我应该更加注意“告诉,不要问”,我正在努力 了解这个问题的原则。
我采用了一种创建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());
这两种方法都有优势吗?还有其他事情我还没有考虑过吗?
答案 0 :(得分:1)
首先,原则上有一点错误:它的“Tell, don't ask”:)。你可以找到关于这个和其他原则here的非常好的文章。基本的想法是,不要向对象提问,然后决定做什么,而应该告诉对象该做什么。每个对象(例如,基于其内部状态)应该知道如何处理任务(消息发送)。 这对于保持责任分配很重要。如果你向某个对象提问,但决定在另一个对象中做什么,那么你就会将一个对象的内在逻辑分散到许多对象中。这会产生难以测试和维护的代码,因为您没有内聚对象和单个位置来修改/测试功能。 这里出现的第二个问题是封装;在大多数情况下,对象的状态是私有的,人们将其公开,以便可以查询对象的状态以便稍后执行操作。作为一般的经验法则,我认为这是一种气味,因为你(再次)不仅将对象的责任传播到系统的其他部分,而且还违反了对象的封装。请注意,我在这里并不是说吸气剂本身很糟糕,只是如果你需要让你的状态公开以便其他对象可以为你做出决定,那么你可能会走错路。
现在,转到你的代码,我认为第一种方法是完全有效的,因为它是知道如何将自己添加到列表中的对象以及应该使用哪些属性。如果需要,您将保持责任分配,内部状态将被封装。
HTH