Code Complete 2ed, состав и делегирование
После нескольких недель чтения на этом форуме я подумал, что пришло время сделать мой первый пост.
Я сейчас перечитываю Code Complete. Я думаю, что прошло 15 лет с прошлого раза, и я обнаружил, что до сих пор не могу писать код;-)
В любом случае на странице 138 в Code Complete вы найдете этот пример ужаса кодирования. (Я удалил часть кода)
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();
И это не хорошо в отношении закона Деметры.
Поэтому, если вы хотите удалить две из трех точек, вам нужно использовать делегирование и несколько функций-оболочек, подобных этой.
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();
Но опять же у вас есть подпрограммы, которые не имеют логической связи.
Я лично считаю, что все три примера в этом посте плохие. Это какой-то другой способ, о котором я не думал?
3 ответа
Сейчас платят сейчас, а платят позже.
Вы можете написать функции делегирования и обертки заранее (заплатите сейчас), а затем у вас будет меньше работы по изменению внутреннего значения employee.IsZipCodeValid () позже. Или вы можете проложить туннель к IsZipCodeValid, написав
. Employee.GetAddress () GetZipCode () IsValid ().везде, где это нужно в коде, но заплатите позже, если вы решите изменить дизайн своего класса таким образом, который нарушает этот код.
Вы можете выбрать свой яд.;)
Вам не хватает логического соединения:
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();
Поскольку между классом Employee и проверкой почтового индекса нет логической связи, вы можете поместить проверку почтового индекса в класс Address, к которому он более логически относится. Затем вы можете попросить класс Address подтвердить для вас почтовый индекс.
class Address
{
public:
static IsZipValid(ZipCode zip) { return zip.isValid(); }
};
Тогда вы делаете
Address::IsZipValid(employee.GetAddress().GetZipCode());
Я думаю, что это удовлетворительно при ваших ограничениях логической ассоциации и закона Деметры.