I am trying to implement a very clean Command Pattern in a library.
I have the following structure right now (a few parts are still being finished up):
Manager
holds a collection of shared_ptr<Foo>
Manager
provides access to the collection by returning shared_ptr<Foo>
Command
abstract class and a hierarchy of commands for actions to perform on Foo
Command::execute()
, only Manager
should, Manager::execute(shared_ptr<Command>)
, so that it can handle undo/redoI would like to follow the following rules:
Manager
holds a collection of shared_ptr<Foo>
Manager
provides access to the collection by returning shared_ptr<const Foo>
Command
abstract class and a hierarchy of commands for actions to perform on Foo
Command::execute()
, only Manager
can, Manager::execute(shared_ptr<Command>)
, so that it can handle undo/redo and get non-const smart pointersManager
must be able to allow Command
objects to access and modify shared_ptr<Foo>
even though the user initializes Command
objecst with shared_ptr<const Foo>
I am just trying to figure out the best way to handle giving out shared_ptr<const Foo>
while allowing number 5 and 6 to work.
Is there any example/design pattern that does this which I could learn from? Is this a good idea compared to what I already have/am working on?
Since it wouldn't make any sense to me otherwise, I'm going to assume that
Manager
class (or at least a base class), andCommand
.In that case, maybe something like this could work:
void Manager::execute(Command& cmd, shared_ptr<Foo const> const& target)
{
shared_ptr<Foo> mutableTarget = this->LookupMutableFoo(mutableTarget); // throws if not found
cmd.execute(mutableTarget); // client cannot invoke without mutable pointer
}
// or, if the "target" needs to be stored in the Command you could use something like this:
void Manager::execute(Command& cmd)
{
shared_ptr<Foo> mutableTarget = this->LookupMutableFoo(cmd.GetTarget()); // throws if not found
cmd.execute(mutableTarget); // client cannot invoke without mutable pointer
}
I'm not sure though if using const
is the best solution here. Maybe you should wrap your Foo
objects in e.g. ClientFoo
objects. The manager only hands out pointers to ClientFoo
. The manager can then (e.g. via friend
) get the Foo
from the ClientFoo
, and use it to invoke the Command
.