Use of 'friend'

Started by
6 comments, last by jpetrie 16 years, 9 months ago
I have both a script and a script_manager class. The manager is responsible for updating an array of script instances that it holds in a std::list<>. Pretty straight forward, but the update member in the script class is private (and I'd like it to stay that way). In order to let the script_manager call script::update(), I've made the script_manager class a friend of the script class - is this justified or am I covering up for a bad design decision?
Advertisement
You are covering up for a bad design decision. The Script and ScriptManager are too coupled, you should make it so the Script does not depend on the existence of the ScriptManager to work correctly—i.e. describe what a script is, and how it should be used, without making references to (or assuming the existence of) a manager for scripts— and only then introduce the ScriptManager.
Granting friendship to functions is an acceptable usage, usually. Granting friendship to entire classes might occasionally be justified, but usually means you're covering up for bad or lazy design (and in this case, definitely seems to mean that).
So ideally Script::Update() should be public and function correctly regardless of whether my ScriptManager calls it or not. In other words Main() could make a call to it?

The use of a ScriptManager should just make performing the same task on many Scripts easier.

i.e.

pManager->Update();

as opposed to...

pScript1->Update();
pScript2->Update();
pScript3->Update();
Essentially, yes. Eventually you may come to realize that ScriptManager serves no useful purpose and can be removed. That's what happened to all of my manager classes over the years as I realized they were mostly crutches for not wanting to think about the problem.

The only thing I have left is a couple caches for doing LRU management of resources and such.
Quote:Original post by FunLogic
The use of a ScriptManager should just make performing the same task on many Scripts easier.


If that is all a manager does, I would possibly drop the use of a manager class altogether, and use a free-standing function instead:

template <typename It>void UpdateScripts(It start, It end){  struct   {     void operator() (Script* s) { s->Update(); }  }   Updater;    std::for_each(start,end,Updater);}// Usage example:std::vector<Script*> monsterScripts;UpdateScripts(monsterScripts.begin(), monsterScripts.end());


Quote:Original post by ToohrVyk
If that is all a manager does, I would possibly drop the use of a manager class altogether, and use a free-standing function instead:

*** Source Snippet Removed ***


Not to derail the thread, but what would you do in C# or Java? Create a class with a single public static function? This is one of the habits I'm trying to break in my own projects currently. Manager classes that support adding/removing items and delegating function calls. Glorified containers basically.
Quote:
Not to derail the thread, but what would you do in C# or Java? Create a class with a single public static function?

Yes.

Chances are, though, that you don't need to update all the scripts in too many places, and such a utility method could just be a member of the class doing the update... It's sort of iffy whether or not you'd even need a separate method for it, since the iteration syntax in C# (at least) is a much more compact
foreach(Script script in listOfScripts)  script.Update();

in this simple example. Of course if more work is involved, that changes things.

This topic is closed to new replies.

Advertisement