在这个论坛上看了几个星期后,我觉得是时候做我的第一篇文章了。
我目前正在重读“代码完成”。我认为这是自上次以来的15年,我发现我仍然无法编写代码;-)
无论如何,在Code Complete的第138页,你会发现这个编码恐怖的例子。 (我删除了一些代码)
class Emplyee {
public:
FullName GetName() const;
Address GetAddress() const;
PhoneNumber GetWorkPhone() const;
...
bool IsZipCodeValid( Address address);
...
private:
...
}
史蒂夫认为不好的是功能松散相关。或者他写道:“检查邮政编码,电话号码或工作分类的员工和例程之间没有逻辑联系”
好的,我完全赞同他。也许类似下面的例子更好。
class ZipCode
{
public:
bool IsValid() const;
...
}
class Address {
public:
ZipCode GetZipCode() const;
...
}
class Employee {
public:
Address GetAddress() const;
...
}
检查拉链是否有效时,您需要执行以下操作。
employee.GetAddress().GetZipCode().IsValid();
这对于Law of Demeter来说并不好。
因此,如果你想删除三个点中的两个,你需要使用委托和一些像这样的包装函数。
class ZipCode
{
public:
bool IsValid();
}
class Address {
public:
ZipCode GetZipCode() const;
bool IsZipCodeValid() {return GetZipCode()->IsValid());
}
class Employee {
public:
FullName GetName() const;
Address GetAddress() const;
bool IsZipCodeValid() {return GetAddress()->IsZipCodeValid());
PhoneNumber GetWorkPhone() const;
}
employee.IsZipCodeValid();
但是你再次拥有没有逻辑联系的例程。
我个人认为这篇文章中的所有三个例子都很糟糕。这是我没想过的其他方式吗?
答案 0 :(得分:7)
您缺少逻辑连接:
class ZipCode
{
public:
bool IsValid();
}
class Address {
public:
ZipCode GetZipCode() const;
bool IsAddressValid();
bool IsValid() {return GetZipCode()->IsValid() && IsAddressValid());
}
class Employee {
public:
FullName GetName() const;
Address GetAddress() const;
bool IsEmployeeValid();
bool IsValid() {return GetAddress()->IseValid() && IsEmployeeValid());
PhoneNumber GetWorkPhone() const;
}
employee.IsValid();
答案 1 :(得分:1)
现在是付费而不是稍后付款。
您可以预先编写委托和包装函数(立即付款),然后更少工作更改employee.IsZipCodeValid()的内部。或者,您可以通过在代码中的任何位置编写
employee.GetAddress().GetZipCode().IsValid();来遍历IsZipCodeValid,但如果您决定以破坏此代码的方式更改类设计,则需要付费。
< / p>
你可以选择你的毒药。 ;)
答案 2 :(得分:0)
由于Employee类和邮政编码验证之间没有逻辑连接,因此您可以将Zip代码验证放入更符合逻辑的Address类中。然后,您可以要求Address类为您验证Zip代码。
class Address
{
public:
static IsZipValid(ZipCode zip) { return zip.isValid(); }
};
然后你做
Address::IsZipValid(employee.GetAddress().GetZipCode());
我认为在你的逻辑关联和德米特定律的限制下,这是令人满意的。