Separate Query from Modifer
将查询函数和修改函数分离
大佬[Meyer]说:某个函数既返回对象状态值,又修改对象状态。建立两个不同的函数,其中一个负责查询,另一个负责修改。
例如,有这样一个函数,一旦有人入侵安全系统,它会告诉我入侵者的名字,并发送一个警报。如果入侵者不止一个,也只发送一条警报:
String foundMiscreant(String[] people)
{
for (int i = 0; i < people.length; ++i)
{
if (people[i].equals("Don"))
{
sendAlert();
return "Don";
}
if (people[i].equals("John"))
{
sendAlert();
return "John";
}
}
return "";
}
该函数被下列代码调用:
void checkSecurity(String[] people)
{
String found = foundMiscreant(people);
someLaterCode(found);
}
为了将查询动作和修改动作分开,我首先建立一个适当的查询函数,使其与修改函数返回相同的值,但不造成任何副作用:
String foundPerson(String[] people)
{
for (int i = 0; i < people.length; ++i)
{
if (people[i].equals("Don"))
return "Don";
if (people[i].equals("John"))
return "John";
}
return "";
}
然后,我要逐一替换原函数内所有的return语句,改调用新建的查询函数。每次替换后,编译并测试。这一步完成之后,原函数如下所示:
String foundMiscreant(String[] people)
{
for (int i = 0; i < people.length; i++)
{
if (people[i].equals("Don"))
{
sendAlert();
return foundPerson(people);
}
if (people[i].equals("John"))
{
sendAlert();
return foundPerson(people);
}
}
return foundPerson(people);
}
现在,我要修改调用者,将原本的单一调用动作替换为两个调用:先调用修改函数,然后调用查询函数:
void checkSecurity(String[] people)
{
foundMiscreant(people);
String found = foundPerson(people);
someLaterCode(found);
}
所有调用都替换完毕后,我就可以将修改函数的返回值改为void:
void foundMiscreant(String[] people)
{
for (int i = 0; i < people.length; i++)
{
if (people[i].equals("Don"))
{
sendAlert();
return;
}
if (people[i].equals("John"))
{
sendAlert();
return;
}
}
}
现在,为原函数改个名称可能会更好一些:
void sendAlert(String[] people)
{
for (int i = 0; i < people.length; i++)
{
if (people[i].equals("Don"))
{
sendAlert();
return;
}
if (people[i].equals("John"))
{
sendAlert();
return;
}
}
}
当然,这种情况下,我得到了大量重复代码,因为修改函数之中使用了与查询函数相同的代码。现在我可以对修改函数实施Substitute Algorithm (139),设法让它再简洁一些:
void sendAlert(String[] people)
{
if (!foundPerson(people).equals(""))
sendAlert();
}