¿Cómo puedo eliminar / refactorizar una declaración de dependencia «amigo» correctamente?
Los antecedentes de esta pregunta se basan en una muestra práctica en la que quería eliminar una dependencia de "amigo" de un par de clases que se utilizan para administrar el acceso bloqueado de lectura / escritura a un recurso compartido.
Aquí hay una abstracción del diseño estructural original para ese escenario:
Marcado en rojo, existe esta fea dependencia de "amigo" que quiero eliminar del diseño.
En resumen, ¿por qué tengo esto aquí:
ClassAProvider
comparte una referencia a unClassA
sobre un número de acceso simultáneoClient
instanciasClient
las instancias deberían accederClassA
únicamente a través delClassAAccessor
clase auxiliar que gestiona las partes internasClassA
oculta todos los métodos destinados a ser utilizadosClassAAccessor
como protegidoEntoncesClassA
puede asegurar queClient
necesita usar unClassAAccessor
ejemploEste patrón es principalmente útil cuando se trata de garantizar dejar instancias deClassA
en un estado definido, si unClient
la operación se rescata (debido a, por ejemplo, una excepción no detectada). Pensar enClassA
proporcionando operaciones emparejadas (visibles internamente) comolock()
/unlock()
oopen()
/close()
.
Las operaciones de reversión (estado) deberían llamarse en cualquier caso, especialmente cuando un cliente falla debido a una excepción.
Esto se puede manejar de manera segura a través deClassAAcessor
El comportamiento del ciclo de vida, la implementación del destructor puede garantizarlo. El siguiente diagrama de secuencia ilustra cuál es el comportamiento previsto:
AdicionalmenteClient
las instancias pueden lograr un buen control de accesoClassA
fácilmente, simplemente usando bloques de alcance C ++:
// ...
{
ClassAAccessor acc(provider.getClassA());
acc.lock();
// do something exception prone ...
} // safely unlock() ClassA
// ...
Todo bien hasta ahora, pero la dependencia de "amigo" entreClassA
yClassAAccessor
debe eliminarse por varias buenas razones
The following table lists predefined standard elements for UML 1.x that are now obsolete. ... «friend» ...
La mayoría de las reglas y pautas de codificación que he visto prohíben, o desaconsejan, usar un amigo, para evitar la dependencia de las clases de exportación a los amigos. Esto trae algunos problemas serios de mantenimiento.Como dice el título de mi pregunta
¿Cómo puedo eliminar / refactorizar una declaración de amigo correctamente (preferiblemente comenzando en el diseño UML para mis clases)?