Sign in to follow this  
Helter Skelter

Todays Tip: Parameterized Proxy

Recommended Posts

One of the problems people may run into when designing various libraries (game engine, ai engine, editor, etc.) is that they end up with classes that are very similar but reside in unrelated class heirarchies. If those classes are required by a single component (e.g. game engine or map editor) they may encounter brainlock when attempting to get everything to work well together. This may involve redesigning one or more classes, trying to use multiple inheritence (which may result in hard to overcome ambiguities), or creating multiple proxy objects. Unfortunately clear and/or workable solutions may not be readily apparent - especially for beginner or even intermediate level programmers - even if the design is very solid. So I figured I would start posting little code snippets that provide possible solutions to various problems like the one described above. These are going ot be posted for simplicity and clarity rather than as an approach to all problems. This should hopefully make it a bit easier for beginners to understand. Todays snippet is the "Parameterized Proxy" using templates rather than multiple inheritence or excessive redesign in order to make similar objects from different code bases work together. Example Problem: An application needs to handle timer events generated by similar classes residing in two unrelated code bases. Solutions: Proxies, containers, redesign, modification of event objects, and multiple inheritence are all possible but may introduce additional issues such as ambiguities of methods or type conversion and duplication of similar code in implementation. Assumption: All event objects include a method called "Fire()" which is called when the event is triggered. Also assumes that redesign or changing the base classes would break a significant amount of existing code. Approach: In order to reduce the amount of duplicate code, parameterized proxy classes are used rather than implementing a proxy for each class that generates an event. Advanced topics: this approach can be made more extensible through the use of Adapters and additional patterns that apply to specific situations. Language trick: Beginner and even intermediate level programmers may not be aware the an argument passed to a parameterized class (template) can be used as the base class in the declaration.
/*****************************************************************************
* Example event owner:
*  This object would be called any time that a timer event is fired
*****************************************************************************/
class CEventOwner {
public:
	// Method that gets called on all timer events
	virtual void Fire() { }
};


/*****************************************************************************
* Timer Event: MFC Based
*  This represents an MFC timer event
*****************************************************************************/
class CMFCTimerEvent {
	virtual void Fire() = 0;
};


/*****************************************************************************
* Timer Event: Win32 API Based
*  This represents a Win32 API timer event
*****************************************************************************/
class CWinTimerEvent {
	virtual void Fire() = 0;
};


/*****************************************************************************
* Timer event proxy:
*  The timer event proxy accepts events triggered by an unknown object
*  (_BASE) and pass it on to a known object (CEventOwner). This allows
*  an application to use a single interface to handle events generated
*  by different [normally incompatible] frameworks.
*****************************************************************************/
template<typename _BASE> class CEventProxyT : public _BASE {

	// Who's you're daddy!
	CEventOwner *m_Owner;

	// Pass the event on to the owner
	virtual void Fire() {
		m_Owner->Fire();
	}

public:
	// Constructor
	CEventProxyT(CEventOwner *owner) {
		m_Owner = owner;
	}

};


/*****************************************************************************
* Declare individual proxy types. by using 'typedef' rather than a simple
* class declaration eliminates the possible need to implement various
* constructors which may be required by the base class. In this instance,
* even with using 'typedef', type safety remains strong.
*****************************************************************************/
typedef CEventProxyT<CMFCTimerEvent>	CMFCTimerEventProxy;
typedef CEventProxyT<CWinTimerEvent>	CWinTimerEventProxy;


// Simple test
CEventOwner owner;
CMFCTimerEventProxy a(&owner);
CWinTimerEventProxy b(&owner);
**These are just POSSIBLE solutions. Not the ABSOLUTE solution***

Share this post


Link to post
Share on other sites
Personally, I prefer the use of functors over the 'common base class' method. They work much more neatly out of the box, and don't require the ->Fire() assumption. Assumptions like that I've found tend to lead to ->Fire() everywhere, which is slightly confusing, and leads to lower re-use.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this