over español edition code 2nd c++ delegates composition code-complete

c++ - edition - code complete español



Code Complete 2ed, composición y delegación (3)

Después de un par de semanas leyendo en este foro, pensé que era hora de hacer mi primera publicación.

Actualmente estoy releyendo Code Complete. Creo que han pasado 15 años desde la última vez, y me parece que aún no puedo escribir el código ;-)

De todos modos en la página 138 en Code Complete encontrará este ejemplo de horror de codificación. (He eliminado parte del código)

class Emplyee { public: FullName GetName() const; Address GetAddress() const; PhoneNumber GetWorkPhone() const; ... bool IsZipCodeValid( Address address); ... private: ... }

Lo que Steve cree que es malo es que las funciones están vagamente relacionadas. ¿O ha escrito "No hay una conexión lógica entre los empleados y las rutinas que verifican los códigos postales, los números de teléfono o las clasificaciones de trabajo"?

Ok, estoy totalmente de acuerdo con él. Quizás algo como el siguiente ejemplo sea mejor.

class ZipCode { public: bool IsValid() const; ... } class Address { public: ZipCode GetZipCode() const; ... } class Employee { public: Address GetAddress() const; ... }

Al verificar si el zip es válido, deberías hacer algo como esto.

employee.GetAddress().GetZipCode().IsValid();

Y eso no es bueno con respecto a la Ley de Demeter .

Entonces, si desea eliminar dos de los tres puntos, debe usar la delegación y un par de funciones de envoltura como esta.

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();

Pero, de nuevo, tienes rutinas que no tienen una conexión lógica.

Personalmente creo que los tres ejemplos en esta publicación son malos. ¿Es de alguna otra manera en la que no he pensado?


Como no existe una conexión lógica entre la clase Employee y la validación de código postal, puede poner la validación del código postal en la clase Address donde más lógicamente pertenece. Luego puede pedirle a la clase de Dirección que valide el código postal por usted.

class Address { public: static IsZipValid(ZipCode zip) { return zip.isValid(); } };

Entonces lo haces

Address::IsZipValid(employee.GetAddress().GetZipCode());

Creo que esto es satisfactorio bajo sus restricciones de asociación lógica y Ley de Demeter.


Es pagar ahora y pagar más tarde.

Puede escribir las funciones de delegación y envoltura por adelantado (pague ahora) y luego tener menos trabajo cambiando las entrañas de employee.IsZipCodeValid () más adelante. O bien, puede acceder a IsZipCodeValid escribiendo

employee.GetAddress().GetZipCode().IsValid(); donde sea que lo necesite en el código, pero pague más tarde si decide cambiar el diseño de su clase de una manera que rompa este código.

Tienes que elegir tu veneno. ;)


Te estás perdiendo la conexión lógica:

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();