friendship case - good or bad

W

werasm

I've read the following somewhere:

"Friendship is the strongest form of coupling there is. That is, you
introduce a high degree of dependency when you declare a friend, since
the friend becomes aware of the private details of a class. This means
that it is more difficult to change those private details, since there
are other things around that depend on them. It doesn't necessarily
indicate poor design, but a design that doesn't use friends may be
preferable to one that does."

Whilst fully agreeing with it, I suppose friendship could be a good
tool (enhance encapsulation) if an interface dictates who may use it.
Often an interface (or ABC) is realized by its client. It makes
natural sense that only its client should use it (and is often the
intent). This does not provide any additional coupling as the client
is already coupled to the ABC.

The simplest way to achieve this (only client code being allowed to
access a particular interface) is by friendship.

For instance:

//Commit only to be called by GenTblReader.
// Implementation commits data read (from IO)
// for use...
template <class RecordT>
class GenTblCommitIF
{
friend class GenTblReader<RecordT>;
virtual void commitTbl( const std::vector<RecordT> tbl ) throw() =
0;
};

//Responsible for commiting data read from disk
// to database... associated with GenTblCommitIF...
template <class RecordT>
class GenTblReader;

// Gives access to tables, and allows committing
// of new data read from IO
class Database
: GenTblCommitIF<RecordA>,
GenTblCommitIF<RecordB>,
GenTblCommitIF<RecordC>
{
private:
//Implement commits - only callable by correct class
};

While the private inheritance from GenTblCommitIF already
provides the necessary encapsulation to prevent erroneous
calling, it implies that Database needs to provide the
dependency to the applicable GenTblReader (or interface
client). If we use friendship to dictate who may use the
interface, the associating (or setting up of dependencies)
becomes much easier due to use not having to inherit
privately to promote encapsulation.

Does this make sense?

Declaring friends in interfaces (ABCs) promote encapsulation,
and reduce dependencies required to realise associations.

Regards,

Werner
 
T

Tristan Wibberley

I've read the following somewhere:

"Friendship is the strongest form of coupling there is. That is, you
introduce a high degree of dependency when you declare a friend, since
the friend becomes aware of the private details of a class. This means
that it is more difficult to change those private details, since there
are other things around that depend on them. It doesn't necessarily
indicate poor design, but a design that doesn't use friends may be
preferable to one that does."

I would say member functions were slightly more strongly coupled.
Whilst fully agreeing with it, I suppose friendship could be a good
tool (enhance encapsulation) if an interface dictates who may use it.
Often an interface (or ABC) is realized by its client. It makes
natural sense that only its client should use it (and is often the
intent). This does not provide any additional coupling as the client
is already coupled to the ABC.

friends of classes that are supposed to be OO-ish (ie inherit from an
abstract base class) are probably a bad idea, yeah, but OO isn't the
only way to do things and is often the wrong choice. But for other
styles of programming (and for the abstract base class) they merely
define a part of the interface to the class where you can use instances
of the class in ways other than "name.member()". You could support
foo(name) without requiring an equivalent public "foo_impl" member (it
can be private or protected instead) as an example. If the thing you
are making into a friend is a part of the interface to the class then
it is *supposed* to be tightly coupled.

--
Tristan Wibberley

Any opinion expressed is mine (or else I'm playing devils advocate for
the sake of a good argument). My employer had nothing to do with this
communication.
 
J

Joe Greer

I would say member functions were slightly more strongly coupled.


friends of classes that are supposed to be OO-ish (ie inherit from an
abstract base class) are probably a bad idea, yeah, but OO isn't the
only way to do things and is often the wrong choice. But for other
styles of programming (and for the abstract base class) they merely
define a part of the interface to the class where you can use
instances of the class in ways other than "name.member()". You could
support foo(name) without requiring an equivalent public "foo_impl"
member (it can be private or protected instead) as an example. If the
thing you are making into a friend is a part of the interface to the
class then it is *supposed* to be tightly coupled.

Sadly, what we really need is a module system so that we can develop
classes and interfaces that require systems of objects to implement and
yet only expose the interface we want to our end user. Unfortunately,
today we only have friendship to allow classes which need to know more
of our internals than our target users, but this allows access to
everything. Interestingly enough, there is a pattern called "Private
Interface" that can be used to help in this situation. The idea is that
you create an interface that you want a specific instance of a class to
use and then inherit it privately. You can (but don't have to) make all
of the implementation methods private. At somepoint, you can pass your
interface to another class and it can then call those methods through
the interface even though no one else can. This method can eliminate
the need for friendship, but is somewhat more inconvenient. It does
break that strong dependency though.

example:

struct IOnlyForHelpers
{
virtual int GetValue() = 0;
virtual void DoSomethingSpecial() = 0;
}

class HelperClass
{
IOnlyForHelpers * m_pMainDude;

public:
HelperClass(IOnlyForHelpers * pMainDude) : m_pMainDude(pMainDude)
{}
void HelpMe() {
if (m_pMainDude->GetValue() > 0)
m_pMainDude->DoSomethingSpecial();
}
};

class MainDude : private IOnlyForHelpers
{
HelperClass * m_pHelper;
public:
MainDude()
{ m_pHelper = new HelperClass(this); }

private:
virtual int GetValue() { return 5; }
virtual void DoSomethingSpecial() { /* something */ }
}

Hope that helps in some way,
joe
 
W

werasm

Joe Greer wrote:

Sadly, what we really need is a module system so that we can develop
classes and interfaces that require systems of objects to implement and
yet only expose the interface we want to our end user. Unfortunately,
today we only have friendship to allow classes which need to know more
of our internals than our target users, but this allows access to
everything. Interestingly enough, there is a pattern called "Private
Interface" that can be used to help in this situation.

I've seen this pattern (ACCU) and my original post, although not
stated is a comment on that. The point is that with private
inheritance, only the implementation can dictate the interface,
but that implies that the implementation requires some kind of
way (another interface?) to dictate this interface.

OTOH, if you have a <true> private interface, the interface itself
has only private virtual functions, and dictates the client that would
use it by making it a friend. Usually clients exist before interfaces
do, in fact, interfaces are most often realized by clients. Therefore
it makes sense that the interfaces dictate who uses them - the client
that realized them, by only allowing them access. Now normal public
inheritance can be used (as it is in fact a true isA relationship),
and
creating the associations is less of a burden.

Regards,

Werner
 
W

werasm

werasm wrote:

OTOH said:
has only private virtual functions, and dictates the client that would
use it by making it a friend. Usually clients exist before interfaces
do, in fact, interfaces are most often realized by clients. Therefore
it makes sense that the interfaces dictate who uses them - the client
that realized them, by only allowing them access. Now normal public
inheritance can be used (as it is in fact a true isA relationship),
and
creating the associations is less of a burden.

Also note that in this case, no additional dependencies exist, as
a client is fully dependent on the interface that it uses anyway,
therefore making it a friend does not make it more dependent.

For instance:

class ClientService
{
virtual void service() = 0;
friend class Client;
};

Does this imply client is more dependent? No.
Friendship enhanced encapsulation...

W
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top