🔒 Locked
Middleware Development Help
Advertisement
Original Post
Alright, I just need some quick help with some of my development concerns. Right now I am developing some middleware, and as everyone knows, middleware should be easily integrated into existing engines. Basically, I want the user to be able to "plug" their own implementations for vectors, matrices, file handling, and other things into the middleware, and then the middleware will use their implementation. So my solution: I create an abstract interface for the user implementation to adhere to, and then I create an abstract interface for a factory class, with one function, that the user must implement. The user then registers their factory class, and the engine uses that factory class to create the objects without any idea of the underlying implementation. Does this seem reasonable? Is there a better way to do it?
provide templates that require them.
provide the classes yourself then all they have to do is write conversion constructors or use them as is.
provide the classes yourself then all they have to do is write conversion constructors or use them as is.
Quote:
Original post by stonemetal
provide templates that require them.
provide the classes yourself then all they have to do is write conversion constructors or use them as is.
I don't quite understand your first explanation, can you explain that. And your second example does seem alright, but then the class I provide does not use their implementation, which could be optimized for some special cases or something.
Quote:
Original post by dmail
Forcing vector, matrix and file handling class' to derive from you base class is just bad design, take some time to learn what good middleware design involves. For example this blog post by Kyle Wilson and the presentation I link to in the comments.
That link doesn't work.
Quote:That link is going in bookmarks forthwith.
Original post by dmail
Forcing vector, matrix and file handling class' to derive from your base class is just bad design, take some time to learn what good middleware design involves. For example this blog post by Kyle Wilson and the presentation I link to in the comments.
Quote:
Original post by swiftcoder Quote:That link is going in bookmarks forthwith.
Original post by dmail
Forcing vector, matrix and file handling class' to derive from your base class is just bad design, take some time to learn what good middleware design involves. For example this blog post by Kyle Wilson and the presentation I link to in the comments.
Odd, it works for me now too. I guess I will have a read then.
EDIT:
Ah, you fixed the link, that's why. But at any rate, I have read that article before when I was searching the internet for answers to my question. This is the exact reason why I wrote, "Basically, I want the user to be able to "plug" their own implementations for...file handling..."
Currently, I have no answers on how to do this efficiently.
Did you also listen to the presentation?
If you are going to be doing matrix and vector operations then you need to use you own representation (or a well defined implementation), yet not force the user of your library to have to use it. Instead give them options by supplying more than one method of informing you of a matrix or vector.
Most math libraries have a conversion to a block of data from a class in the form of float* or double* so having this option is really a must. The presentation makes the point of writing user code before library code, ie what will your uses have to do, so ...
You could also support the DirectX math library directly in a windows build or at least give the user the option, possibly also giving the user the _option_ of using your libraries fancy matrix type. Another possibility is to document your matrix type and say to the user here is a abstract class derive from it with an implementation of converting from my type to yours and vice versa and tell the library about it. You could also have an option which accepts 16 floats or ...
If you are going to be doing matrix and vector operations then you need to use you own representation (or a well defined implementation), yet not force the user of your library to have to use it. Instead give them options by supplying more than one method of informing you of a matrix or vector.
Most math libraries have a conversion to a block of data from a class in the form of float* or double* so having this option is really a must. The presentation makes the point of writing user code before library code, ie what will your uses have to do, so ...
enum MATRIX_ORDER{ROW,COLUMN}; void Lib::bar(float*);void Lib::set_matrix_order(COLUMN);//initialise the lib...//user codeD3DXMATRIX foo;Lib::bar(foo);//D3DXMATRIX has the conversion and the library knows the layout.You could also support the DirectX math library directly in a windows build or at least give the user the option, possibly also giving the user the _option_ of using your libraries fancy matrix type. Another possibility is to document your matrix type and say to the user here is a abstract class derive from it with an implementation of converting from my type to yours and vice versa and tell the library about it. You could also have an option which accepts 16 floats or ...
Quote:Don't. I've seen it tried, and it doesn't work, and it sucks. Manually written conversion functions, mildly annoying though they may be, are the way to go. Just make sure to store your matrices in the same order as everyone else, so that conversion functions are no-ops.
Original post by Halifax2
Basically, I want the user to be able to "plug" their own implementations for vectors, matrices
Quote:
file handling
This one's a better idea, and it's also a lot easier. The way you proposed will work fine. Consider, though, how streaming will affect things.
If your middleware is distributed with full source code, then you could use the client/engine's math classes within your code, by including the engine's math code within your middleware's code.
E.g.
This means you're using your own interface (not virtual tho) but you can actually just be using their classes behind that interface.
E.g.
// my_math.h#ifdef USING_GAMEBRYO_ENGINE# include <gamebryo_SDK/math.h># include "gamebryo_math.h"#else# ifdef USING_UNREAL3_ENGINE# include <unreal_SDK/math.h># include "unreal3_math.h"# else# include "backup_math.h"# endif#endif// backup_math.hclass MyVec3{ MyVec3() : x(0), y(0), z(0) {} MyVec3( const MyVec3& o ) : x(o.x), y(o.y), z(o.z) {} MyVec3& operator+=( const MyVec3& rhs ) { x+=rhs.x; ... return *this; } float X() const { return x; }//etc...private: float x,y,z;}// gamebryo_math.hclass MyVec3 : public NiPoint3{ MyVec3() : NiPoint3(0,0,0) {} MyVec3( const NiPoint3& o ) : NiPoint3(o) {} MyVec3& operator+=( const MyVec3& rhs ) { NiPoint3::operator+=(rhs); return *this; } float X() const { return m_flX; }//etc...}This means you're using your own interface (not virtual tho) but you can actually just be using their classes behind that interface.
Quote:
Original post by Halifax2
So my solution: I create an abstract interface for the user implementation to adhere to, and then I create an abstract interface for a factory class, with one function, that the user must implement. The user then registers their factory class, and the engine uses that factory class to create the objects without any idea of the underlying implementation.
I'm sorry to be a bit blunt, but if you don't see that this is an absolutely horrible idea for vector and matrix classes (for file classes it's ok though), then I don't think you are ready to develop any viable middleware yet.
About those math classes, I would really just suggest you to use your own implementation, which would exist side by side with the math classes the users own code uses. This is how pretty much all middleware does it, and it's like the least problematic thing when integrating middleware into an existing engine.
And a personal opinion of mine: It's definitely a good idea to give the user the option to provide their own file handling to the middleware, but I really think it should be optional, and not be something the user has to implement, before it can even start using your middleware. Always provide a simple fallback to something like a fopen based implementation or so, just so it will be easier for the users to get started with trying it out a bit.
Quote:
Original post by Halifax2
So my solution: I create an abstract interface for the user implementation to adhere to, and then I create an abstract interface for a factory class, with one function, that the user must implement. The user then registers their factory class, and the engine uses that factory class to create the objects without any idea of the underlying implementation.
A good design philosophy for these kinds of things it to make sure you implement your memory allocation, file management, debug output and anything you want pluggable as plugins yourself. For example, if you support reading from a file, you'll need a way to open a file, read from a file, and close the file. I can imagine you might provide an abstract interface IFileRoutines that can be implemented by the end user and handed to the library on startup. In one case, you might write:
if ( pFileRoutinesInterface ) pFileRoutinesInterface->Read(...);else fread( fp, data, ... );Instead implement the built-in file handling as a concrete implementation of the IFileRoutines class so that it excersises the same interface as the end user. You can additionally provide the source code for the default implementation so that people can see and cut and paste to get started.
I find this works really well for making sure you provide all the hooks to the end user - if you suddenly realise you need fseek you won't forget to add it to the IFileRoutines interface.
As far as the math routines go, I'm with everyone else - the implementation details of a math library should be considered internal functions of your middleware package - the client code should use their own math library and pass the data to yours. This is exactly how all the middelware products I've ever seen work.
That article about middleware was great. Going to have to put that in my reference list.
S.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement