Command design pattern with friend class in C++

197 Views Asked by At

The situation: I have to handle and take action on various commands, which can be encapsulated in the command design pattern. So right now I have

class Command {
    virtual void applyCommand(IFoo& foo) = 0;
    virtual ~Command() = default;
};

and of course I inherit this interface into my individual command classes.

However now, I realize that just passing IFoo isn't enough. I want to be able to access private data members in my ConcreteFoo class. I justify this break in encapsulation because when it comes down to it, all these objects are basically just helper functions for my ConcreteFoo class. I'm fine with them being strongly coupled because one way or the other, I have to write these methods, and doing the CDP makes it more readable.

So, I change my class to

class Command {
    virtual void applyCommand(ConcreteFoo& foo) = 0;
    virtual ~Command() = default;
};

and in my ConcreteFoo class I declare

friend class Command;

However, friendship apparently is not inherited into the subclasses of Command, the classes that actually do the work. So I can't actually get access to the data I need.

My current thoughts on solving this are:

1.) Take the L and just handle this without the CDP

  • possible, but I don't really want to take this route if I can avoid it

2.) Make data members in ConcreteFoo public

  • no

3.) Make data members in ConcreteFoo protected, and somehow make Command a subclass of ConcreteFoo

  • no

4.) Manually declare each Command subclass a friend, so like

friend class CommandA;
friend class CommandB;
friend class CommandC;
friend class CommandD;
...
  • decent, but might not scale well. on the plus side, if I forget to friend, it should fail at compile time

None of these options are particularly appealing to me. Is there something else I can do?

1

There are 1 best solutions below

0
lorro On

You’re basically working on visitor pattern (your Command class is a visitor to Foo classes).

One way to go around this, you might have a public interface of Command (applyCommand non-virtual) and virtual implementation(s) (applyCommandImpl virtual). You can make Command itself a friend and Command::applyCommand could extract the necessary data and pass it to the particular applyCommandImpl.

Normally, you’d simply extract the necessary parameters and pass those. However, if you really want to access all members, then you might do this: have the members of Foo in a struct (say, Foo1DO, as in data object) and inherit from it privately to have Foo1. Then you can have a simple getter to reach Foo1DO from Foo1 in applyCommand.