Archived

This topic is now archived and is closed to further replies.

Objects that 'know their place'

This topic is 5400 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I''ve got a design like the following: Event ------------------------ Connection Filter Output How it works is that a Connection generates an Event, which gets passed down through the Filters to the Outputs, which may or may not touch it. Nothing extraordinary here. Connection, Filter, and Output are derived from a base Component class. They inherit one method, Dispatch(), which must be overridden and defines how the Component reacts to the Event. Filters and Outputs can be loaded from DLLs. Problem is, the DLL entry point returns the base class pointer. I can: a. Cast down to a subclass, but that just circumvents polymorphism and I''ve hardcoded in all the different types I can load (e.g. additional maintenance point) b. Use a differently named Create function for Filters, etc. Even more maintenance. c. Use a field in base class that indicates where the Component should live in the chain. However while this is the best of the solutions it still doesn''t feel right, because it IS a disguised type field, and it does imply that the Component knows that it lives in a chain (e.g. it shouldn''t be concerned with it). What would you do?

Share this post


Link to post
Share on other sites
Why not create a set of intermediate base classes derived from Component called Connection, Filter and Output and have your DLLs derive off those instead of Component. You''ll be able to pass the objects as type Component, but you''ve still got the problem that given a pointer/reference to a Component, you don''t know if it''s a Connection, Filter or Output. I guess these three could implement a ''GetType'' function, virtually defined in Component like your ''c'' solution, but at least all your DLL''s wouldn''t need to implement the function, just derive of the correct sub type.

Other than that, there''s always RTTI (yuk!) and the typeid operator.

Skizz

Share this post


Link to post
Share on other sites
quote:
Original post by Skizz
Why not create a set of intermediate base classes derived from Component called Connection, Filter and Output and have your DLLs derive off those instead of Component. You''ll be able to pass the objects as type Component, but you''ve still got the problem that given a pointer/reference to a Component, you don''t know if it''s a Connection, Filter or Output. I guess these three could implement a ''GetType'' function, virtually defined in Component like your ''c'' solution, but at least all your DLL''s wouldn''t need to implement the function, just derive of the correct sub type.

Other than that, there''s always RTTI (yuk!) and the typeid operator.

Skizz


Yeah I have intermediate base classes exactly like you mentioned, I just forgot to say so.

The c. solution is imperfect but I think its better than RTTI in this case.

Share this post


Link to post
Share on other sites
Hmmm. Maybe if we saw the bigger picture, a better solution would become apparent. Also, I think the term 'Connection' is somewhat misleading. To me, it would imply a method of transferring data from one filter to the next or to the output, not as an object generating events. And 'Dispatch' sounds like a data generator (or source) which would be OK for an event object (i.e. Event->Dispatch () ) but sounds odd for the data sink / the output. I'm not trying to be difficult with these comments, it's just that you know what you mean because you wrote it, whereas I'm stuck with these simple names (naming is a difficult thing to do and it's hard not to imply something to yourself that doesn't exist in the vanilla interpretation).

From what you've described it sounds like you've got graph of filters that are connected together in some predetermined way (defined by a text file, perhaps) and a packet of data (the event) that is passed along the graph, finishing at the output (the intended recipient), much like a rendering pipeline. I'm guessing, therefore, that it's the building of the graph that is the problem (since it's the only place where the exact type of the node/filter is required).

If this is the case, then give each node a unique identifier (a string or a GUID), accessed statically and create a factory class to generate nodes for a given ID. It's a very common solution (even COM uses it) and I don't think there's any 'elegant' way you can do this in C++.

Of course, if my assumptions are wrong then the above is complete bollocks.

Skizz


[edited by - Skizz on March 4, 2003 11:18:00 AM]

Share this post


Link to post
Share on other sites
I''m developing an open source instant messaging client out of this architecture. I can separate the protocols from the methods of displaying it, and allow users to cleanup incoming messages as they see fit with filters, including blocking spam/porn (same thing nowadays) on some networks with the inclusion of filters. That should give the names some context, but if you have better ones to suggest by all means let me know.

As far as ordering, it makes no difference what order the Filters are in, or what order the Displays are in, they all receive every Event generated. Connections are listed as on the chain but in reality there is an object on the end that broadcasts Events to the correct Connection (e.g. you don''t want all of your connections sending the same message).

What does matter is that filters are before displays, and whatnot, and there doesn''t seem to be any elegant way to do this. But then C++ isn''t always elegant, so thats part of the problem.

Share this post


Link to post
Share on other sites
Are you familar with DirectShow? It''s a COM-based pluggable filter-graph implementation (written in C++).

It''s a rather complicated design, but filter graphs are complicated.

I think you need three concepts. A filter, an input pin, and an output pin. A source filter only has output pins (one or more), a display filter only has input pins (one or more). Then the "filter" filters have both input & output pins (again, one or more of each).

Filter''s don''t really care that they are plugged into other filters, just that output pins are plugged into input pins and they agree on the media type (e.g. for your example, ascii, html, unicode, etc..).

- Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

[Look for information | GDNet Start Here | GDNet Search Tool | GDNet FAQ | MSDN RTF[L] | SGI STL Docs | STFW | Asking Smart Questions ]

[Free C++ Libraries | Boost | ACE | Loki | MTL | Blitz++ | wxWindows| Spirit(xBNF)]
[Free C Libraries | zlib ]

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
It's a rather complicated design, but filter graphs are complicated.



Sort of. But I'd like the whole application to be structured around these concepts.

I envision:
1. I double click on a user on the contact list
2. The ContactList component generates a ConversationInitiatedEvent. That is *all* it has to do, as the ContactList component should ONLY deal with displaying the contact list.
3. It gets handed down from displays, to filters, to connections (go backwards on my silly little diagram, I couldn't put the arrows in) until it either falls off the chain (no handlers claim it) or it is claimed, which in this case, would probably be the Conversation plugin, which is also a display plugin.

When I want to send a message, it'd go through the filters on its way to the appropriate Connection. One filter could be a spell-check filter that some people think clients should have.

Every component is two way here. Events that are really just GUI callbacks won't proceed past the displays. The components aren't coupled together. The construction process is, and that is my problem.

My other thought was to make the components be peer to peer, or, to know their previous and next one, but some object has to know how they are assembled, and I still deal with ways to load them from DLLs elegantly.

What do you think?

[edited by - antareus on March 5, 2003 9:58:27 PM]

Share this post


Link to post
Share on other sites