Here's a sample code sample:
// ServiceManagerImpl.h
class ResourceManager;
class SceneManager;
class RenderManager;
struct ServiceManagerImpl {
ResourceManager* resman;
SceneManager* sceneman;
RenderManager* renderman;
};
// ServiceManager.h
struct ServiceManagerImpl;
class ServiceManager {
public:
ServiceManager(ServiceManagerImpl* impl);
public:
template<class ServiceType>
ServiceType* get();
private:
ServiceManagerImpl* impl;
};
// ServiceManager.cpp
#include "ServiceManager.h"
#include "ServiceManagerImpl.h"
ServiceManager::ServiceManager(ServiceManagerImpl* impl) : impl(impl) {
}
template<> ResourceManager* ServiceManager::get() { return impl->resman; }
template<> SceneManager* ServiceManager::get() { return impl->sceneman; }
template<> RenderManager* ServiceManager::get() { return impl->renderman; }
And a sample demonstratation:
// Game.cpp
void Game::Setup() {
ServiceManagerImpl* impl = new ServiceManagerImpl;
impl->resman = new ResourceManager;
impl->renderman = new RenderManager;
impl->sceneman = new SceneManager;
theServiceManager = new ServiceManager(impl);
}
void Game::Dothings() {
for ( int idx = 0; idx < entities.size(); ++idx )
entities[idx]->update(theServiceManager);
}
// MonsterEntity.cpp
#include "MonsterEntity.h" // "ServiceManager.h" (implied)
#include "RenderManager.h"
void MonsterEntity::Update(ServiceManager& services){
services.get<RenderManager>()->renderThing(iDunno);
}
// PlayerEntity.cpp
#include "PlayerEntity.h" // "ServiceManager.h" (implied)
#include "SceneManager.h"
void PlayerEntity::Update(ServiceManager& services) {
services.get<SceneManager>()->currentScene()->setCameraPosition(getPosition());
}
As you can see, a new service can be added to ServiceManagerImpl.h with an accompanying template specialization for ServiceManager::get in ServiceManager.cpp without affecting ServiceManager.h and none of the ServicesManager users need to be recompiled. Only Game.cpp and ServiceManager.cpp need to be recompiled (expensive for Game.cpp, relatively light for ServiceManager.cpp).
I'm not sure how this rates on the OOP-perversion scale, but I think this is pretty neat.
EDIT:
Here's an image illustrating such an approach as well
http://i.imgur.com/rbPhD.png