Policy-based design follow-up

Started by
4 comments, last by hymerman 17 years, 2 months ago
So, after my recent post here I got going on this policy-based factory thing, which seemed to be going quite well until I realised just how much scope the policies will need in my design. I'm no longer sure if I should use policies or actually just completely seperate factory classes, since even the interface will need to change depending on what is being registered in the factory. To recap and expand on the problem: I want a factory that can create and return pointers to instances by name (normal factory behaviour), but that can also return a pointer to an already created instance, depending on the policy. The context is in an audio player; 'Decoder' objects for instance would operate normally (factory<Decoder>.create("Decoder")), but to get 'the GUI' you would want to get a pointer to the first created one (factory<GUI>.create()). Note that multiple GUIs may be registered, but only one will ever be instantiated. Ignore for now how the factory knows which one to instantiate in the first place ;). These behaviours seem to have to operate at slightly different levels; you need a name to get a particular Decoder, but you just want to get the 'default' GUI, without specifying a name. This, plus the fact that 'create' doesn't necessarily create anything in GUI's case, leads me to think that this is actually too big a gap in behaviour to bridge with a policy. So, my question is: is policy-based design appropriate here? If so, how would I approach the problem? If not, er... same question! Thanks for your help, wonderful GameDev.net people! I don't know what I'd do without you!
Advertisement
Apologies for bumping this thread, I didn't want to see it disappear onto the next page without any replies :)

I've been doing some more research, but haven't managed to find anything particularly useful - everything seems to cover overly trivial problems in great detail, but nothing complex is covered, and more importantly nobody describes when to use policies, or their limits. Should I be looking at the strategy pattern also? As far as I understand, the two patterns are somewhat equivalent, but with the policy pattern being implemented at compile time rather than runtime. Is this correct?

And of course, any answers to my first post?
I think you're trying to pile too much responsibility into one class. I'd seperate your factory from your caching mechanism and put each into seperate classes. The cache would be responsible for knowing whether you've got an instance created already or not, and if it needs to create a new one. If it does, then it just defers to the factory to do the actual creation. Does that make your layour any simpler?
If you want to use a policy, then that policy is what is going to decide whether you're creating a new instance of an object or going to a cache to retrieve an already created instance.

Think of it like a strategy-template hybrid design pattern.

Your factory should call out to the specified policy to provide certain behavior.

ObjType* Factory<Policy, ObjType>::Create()
{
...Factory stuff that doesn't change...
Policy::PolicyProvidedBehavior1();
...
Policy::PolicyProvidedBehavior2();
...
}

An example Policy interface might be:
class IPolicy<T>
{
static T* Create() = 0;
static Destroy(T*) = 0;
}

Then you can use your Policy classes to implement those "hooks" that you gave yourself in the Factory's methods. You could create a CachePolicy, a CreateNewPolicy, or even a FreelistPolicy if you want to manage memory efficiently, etc.
I would use a very similar idea:

template <class T> class standard_policy { public:  static T* get_new_instance() { return new T; }  static void destroy_instance(T *p) { delete p; }}; template <class T, class Policy = standard_policy<T> >class factory{public:  static T *create()  {    return Policy::get_new_instance();  }  static void destroy(T *p)  {    Policy::destroy_instance(p);  }};

Template specialization can then be used to provide specific mecanism for some particular classes
template <> class standard_policy<my_important_class>{public:  // singleton like...  static T* get_new_instance()   {     static T instance;    return &instance   }  static void destroy_instance(T *p) { /*nothing*/ }};

However, template specialization should only be used if the overall behavior of the specialized class matches the semantic of the base template class (this is not the case in the example I just provided). To overcome this problem, use another policy class (for example, singleton_like_policy<T>) and pass it as a template parameter to the factory instance:
my_object = factory<my_class, singleton_like_policy<my_class> >::create();


Regards,
Thanks very much, people, that's been quite an insight into how to implement policy-based designs in a useful fashion, I appreciate it a lot :)

However, I'm going to have to split up the functionality into two seperate classes, since they are actually rather different - create(name) vs. get(). Policies shouldn't change the interface to anything (I haven't read that, but it seems obvious, please tell me if I'm wrong!).

This topic is closed to new replies.

Advertisement