The background of this question is based on a practical sample where I wanted to remove a «friend» dependency from a pair of classes that are used to manage read/write locked access to a shared resource.
Here's an abstraction of the original structural design for that scenario:
Marked in red, there's this ugly «friend» dependency I want to remove from the design.
In short, why do I have this thing there:
ClassAProvider
shares a reference to aClassA
over a number of concurrently accessingClient
instancesClient
instances should accessClassA
solely through theClassAAccessor
helper class that manages the internalsClassA
hides all methods intended to be used fromClassAAccessor
as protected.- So
ClassA
can ensure thatClient
needs to use aClassAAccessor
instance
This pattern comes primarily useful, when it's about ensuring to leave instances of ClassA
in a
defined state, if a Client
operation bails out (because of e.g. an uncaught exception). Think of
ClassA
providing (internally visible) paired operations like lock()
/unlock()
or open()
/close()
.
The (state-)reversing operations should be called in any case, especially when a client crashes due
to an exception.
This can be safely handled through the ClassAAcessor
's life cycle behavior, the destructor
implementation can ensure it.
The following sequence diagram illustrates what's the intended behavior:
Additionally Client
instances can achieve a fine control of accessing ClassA
easily, just using
C++ scope blocks:
// ...
{
ClassAAccessor acc(provider.getClassA());
acc.lock();
// do something exception prone ...
} // safely unlock() ClassA
// ...
All fine so far, but the «friend» dependency between ClassA
and ClassAAccessor
should be removed for a number of good reasons
- In the UML 2.2 Superstructure, Section C.2 under Changes from previous UML it says:
The following table lists predefined standard elements for UML 1.x that are now obsolete. ... «friend» ...
- Most coding rules and guidelines I've seen forbid, or strongly discourage using friend, to avoid the tight dependency from the exporting classes to the friends. This thing brings in some serious maintenance issues.
As my question title says
How can I remove/refactor a friend declaration properly (preferably starting out at the UML design for my classes)?