Manually manage and update Intel TBB flow graph? - c++

I have successfully prototyped an application using Intel's awesome TBB flow graph library. It seems to work quite well, but now I need to refactor the code into a production-ready version.
Previously, I have worked with some larger and more "over-developed" frameworks for this particular domain (the work is in image processing and previous applications have used ITK/VTK). For this application, however, I am trying to take a lower-level and more focused approach.
Currently, I am just assembling my entire graph in main() which is obviously not sustainable. I'd like to allow the pipeline to run iteratively so that I can grab output data from each stage and display it for debug/analysis purposes.
My idea so far is to abstract each logical "stage" of the application into a class that accepts a &tbb::flow::graph as a constructor argument and internally stores a reference to the graph node it controls. I can have the wrapper class allocate an additional tbb::flow::broadcast_node at the output and an async node after that to fire off events.
Is this a sensible design concept? Generally speaking, how have others integrated the TBB flow graph concepts into the structure of their application? The examples and documentation are quite scant for this particular portion of the TBB library.

As with any design, I don't think there is a clearly right or wrong way to do it. I don't know your code good enough, but breaking the code up by logical stages is probably a good idea.
When it comes to frameworks like TBB, a design decision that you have to make is whether you should hide all framework aspects behind an interface. The advantage is that you could later swap out the implementation with another implementation (e.g., replace TBB by OpenMP). On the other hand, introducing an additional layer might not be needed in all cases. Especially, if it is unlikely that you will ever replaced TBB.
The design design that you describe in your question is how to structure the framework dependent part. It depends very much on the concrete algorithm that you are implementing. For instance, if it consists of applying separate transformations on one images, creating one class per transformation step could be a good approach.
In addition, it might make sense to wrap everything in a function or class. If the operation that you are implementing takes one image as an input and produces one image as an output, this is something that can be hidden behind an interface that hides the implementation details (in this case TBB).

Related

Handing of C code in C++ (Vulkan)

I am trying to write a rendering engine in C++ based on Vulkan. Vulkan is written in C, as a result it has some interesting conventions.
A recurring pattern I see in tutorials/code snippets from Vulkan apps is that most code is in 1 very big class. (right now my vulkan class is already about 2000 lines too). But to make a proper rendering engine, I will need to compartmentalize my code till some degree.
One of the aforementioned interesting bits is that it has something called a Logical Device, which is an abstract reference to the graphics card.
It is used everywhere, to create and allocate things in the following way:
Create structs with creation info
Create variable that the code will output into
Call the actual vkCreateSomething or vkAllocateSomething function, pass in the logical device,
the creation info and the reference to the variable to output to and check if it was a success.
on its own there is nothing wrong with this style I'd say. It's just that it's not really handy at all in OOP because it relies on the logical device being available everywhere.
How would I deal with this problem? Service locators and singletons are considered to be horrible solutions by many (which I can understand), so that seems like something I'd rather avoid.
Are there design patterns that deal with this?
The logical device is an actual dependency.
It has state, and its state needs to be available to work with the hardware.
You can use it as an argument to your operations, a value stored in pretty much every class, a global, or a monadic-esque "final" argument where every operation just returns something still needing the device to run on. You can replace a (pointer/reference to) it with a function returning a (pointer/reference to) it.
Consider if pure OOP is what you want to do; vulkan and rendering is more about operations than things being operated on. I would want to mix some functional programming patterns in, which makes the monad-like choice more reasonable.
Compose operations on buffers/data. These return operations, which also take buffers and data. The composition operation specifies which arguments are new inputs, and which are consumed by the next step. Doing this you can (at compile time) set up a type-safe graph of work to do, all without running anything.
The resulting composed operation would then have a setup (where you bind the logical device and anything you can do "early" before you need to have the expensive buffers ready), and an execute phase (where you feed it the expensive buffers and it generates output).
Or as another approach, find a compiler with coroutine support from c++2a and write it async yet procedurally.
Vulkan is a OOP API. It is not class-based, because it is C99 not C++. That can easily be fixed by using the official Vulkan-Hpp. You can consume it as vulkan.hpp which is part of the semi-official LunarG Vulkan SDK.
The usage would not be that different from vulkan.h though: you would probably have a member pointer/reference to a Device instance, or would have a VkDevice handle member in each object that needs it. Some higher level object would handle the lifetime of the Logical Device (e.g. your RenderingEngine class or such). The difference would be almost only esthetical: you would use device->command(...) instead of vkCommand(device, ...). vulkan.hpp does not seem to use proper RAII through constructors/destructors which is a shame.
Alternatively the user of your engine can manage the device. Though unlike OpenGL there is not much use for this. The user can make its own VkInstance and VkDevice if it also wishes to use Vulkan for something.
A recurring pattern I see in tutorials/code snippets from Vulkan apps is that most code is in 1 very big class.
That's not really specific to Vulkan. If you think about it, pretty much all C++ applications are one big class doing everything (only differences being how much the programmer bothers to delegate from it to some other class instances).

How to make proper design/architecture of partially reusable algorithm? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am very sorry for the long explanation, but it is required for proper understanding.
I am working on computer vision algorithms for industrial tasks. Computer vision algorithms tend to be very complicate. Usually they involve calls for dozens (at the very least) of simpler algorithms (that are not simple either). Those calls form certain hierarchy: bigger tasks call some smaller ones, which in turn call even smaller ones, and so on.
Let’s take for example typical computer vision task: find object in image under certain conditions. This is a task that should be performed in dozens of different applications. Each application has its own set of conditions and thus it is impossible to create single algorithm that works for all of them. But they are pretty similar. Usually it is enough to replace one or two lower level functions. For example: use different method for detection of points of interest in image.
And here comes a problem: for each new application I had to copy whole code from one of the existing applications and adapt relevant parts, which is a bad practice. I am trying to eliminate those duplications by creating system of algorithms that can be used in all application without changing the code itself. Here is the list of issues system had to deal with (at least the ones I identified so far):
1) Arguments provided to main algorithm should be able to set the 'algorithmic flow' inside the system, i.e. they determine what lower level algorithms are used and how
2) Different sub-algorithms that perform same task may require different inputs. One may need an array of ints, another requires pair of double, and so on... Algorithms on the higher level should be oblivious to replacement of one sub-algorithm with another. That means they should not be aware of what arguments they receive and pass down to sub-algorithms. Same true for output of sub-algorithm. It may vary if different combination of sub-algorithms is used
3) The system must be extendable. If new sub-algorithm became available (for example: yet another way to find points of interest) the system should be able to call it. I understand that changes might be unavoidable at this point, but I would like to keep them at minimum. And in any case the system should be able to work at the same way with previous sets of arguments.
4) System must be debuggable. End user of the system should have reasonable way to dump debug information about the 'algorithmic flow' in his system, so that algorithm developer will be able to recreate the situation. It is not that trivial considering requirement (3).
5) There should be reasonable way to make sanity check for the flow of algorithms.
6) I am not going to throw exceptions but there should be reasonable way to return success / fail status of each algorithm. Again it is not easy because of requirement (3).
7) This one is more 'good to have' rather than 'must have', but it may be important. Some calculations may be performed by multiple sub-algorithms. For example calculation of gradients in image may (or may not) be required for multiple different tasks. It is good to have an option to store results of those calculations in order to reuse them later.
I created some kind of solution to this but it is far from being good. Do you have any recommendations about how this should be done?
Used language: C++
Thanks you
I'd just use some tried and true design patterns.
Use a strategy pattern to represent an algorithm that you may wish to swap out for alternatives.
Use a factory to instantiate different algorithm (strategy) instances based on some input parameter or runtime context - I'm a fan of the prototype factory where you have "inert" instances of each object in some lookup table, and based on a key you pass in you can request a clone of the one needed. I like it mainly because it's easiest to extend - you can even add new configured prototype instances to such a factory at runtime.
Note that the same "strategy" model does not have to serve for everything - it sounds like you might have some higher-level/fuzzy operations which then assemble or chain together low-level/detailed operations. The high level operations could be one type of abstract object while the detailed algorithms are the more concrete strategy instances.
As far as the inputs to the various algorithms, if it varies a lot from algorithm to algorithm you could use an extensible object like a dictionary for parameters so that each algorithm can use just the parameters it needs and ignore the others for an operation. If the dictionary is modifiable during the operation this would also permit upstream algorithms to add parameters for downstream algorithms. Key-value pairs are pretty easy to dump to a log or view in a debugger.
If each strategy instance has a unique semantic identifier you could easily debug the algorithms that get instantiated and chained together. (I use an audio DSP library that has a function to dump a description of the whole chain of configured audio processors, it's very handy).
If you use a system with strategy patterns and extensible parameters you should also be able to segregate shared algorithms from application-specific algorithms, but still have the same basic framework for instantiating and running them.
hth
I'm going to assume that you are a competent OO programmer with good domain knowledge, and your problem is more about a higher level of organisation of software components (implementing algorithms) than OO generally provides.
The patterns mentioned by #orpheist make perfect sense. Consider them. They will not solve all the problems you list. You should also consider the following.
In what form will the data be for algorithms to access?
Will you need adapters to connect one component to another?
Do you pass the data to the component or the component to the data?
Do you want to assemble a pipeline or group of components to build higher ones, which can then be applied to the data?
Do you need a language (XML, DSL) to express connections and to allow for easy experimentation?
Is performance a dominant issue already, or can you afford more interpretive techniques at this stage?
It think you need to refine some of your questions and provide some more concrete specifics. I also think your questions would be a better fit on programmers.stackexchange than here.

Removing dependencies from statechart framework

I've got lots of problems with project i am currently working on. The project is more than 10 years old and it was based on one of those commercial C++ frameworks which were very populary in the 90's. The problem is with statecharts. The framework provides quite common implementation of state pattern. Each state is a separate class, with action on entry, action in state etc. There is a switch which sets current state according to received events.
Devil is hidden in details. That project is enormous. It's something about 2000 KLOC. There is definitely too much statecharts (i've seen "for" loops implemented using statecharts). What's more ... framework allows to embed statechart in another statechart so there are many statecherts with seven or even more levels of nesting. Because statecharts run in different threads, and it's possible to send events between statecharts we have lots of synchronization problems (and big mess in interfaces).
I must admit that scale of this problem is overwhelming and I don't know how to touch it. My first idea was to remove as much code as I can from statecharts and put it into separate classes. Then delegate these classes from statechart to do a job. But in result we will have many separate functions, which logically don't have any specific functionality and any change in statechart architecture will need also a change of that classes and functions.
So I asking for help:
Do you know any books/articles/magic artefacts which can help me to fix this ? I would like to at least separate as much code as I can from statechart without introducing any hidden dependencies and keep separated code maintainable, testable and reusable.
If you have any suggestion how to handle this, please let me know.
The statechart pattern is intended to be used specifically to remove switch statements, so this sounds like a horrid abuse. Additionally, states should only change on asynchronous events. If you are processing an event and you change through multiple states (or for loop, etc.), then this is also a horrid abuse of the pattern.
I would start from these two points, as they will solve much of your concurrency issues just fixing them up. What you need to determine is:
What are your external, asynchronous events to the system? These are the only things that should be determining state transitions, not things that happen during event processing. An event may cause 0 or 1 state transitions. Once you have a list of these state transitions, you can reconstruct the actual states of your system. If you are aware of UML State diagrams, this would be a perfect time to sketch one up in a charting program, not just for yourself (though it will help you immensely), but also for everyone in the future that has to return to the project. As you have learned, this happens.
Now that you know what are really states, list what are states in the code that shouldn't be. This usually indicates that something can be "functionally decomposed". Instead of a state object for each of these, likely all that is needed is a separate function. This will cut down on a lot of the overhead of state objects and should clean up the code immensely.
Now it's time to tackle those horrendous switch statements you mentioned. If they were truly based on state, you shouldn't need one at all. Instead, you should be able to call the state machine directly.
Something like:
myStateMachine->myEvent();
and it should work without any switch. But notice, this may be the case even for some of those objects that don't work across asynchronous events. This is also an indication of where you may just use inheritance to get the same effect. If you have:
switch (someTypeIdentifier)
{
case type1:
doSomething();
break;
case type2:
doSomethingElse();
break;
}
usually the correct OOP method to do is to create two actual types Type1, Type2, both derived from an abstract base TypeBase, with a virtual method doSomething() that does what you need. The reason this is useful is because it means you can "close" the handling (in the meaning of the Open/Closed Principle), and still extend the functionality by adding new derived types as needed (leaving it open to extension). This saves bugs like crazy because it gets developers hands out of those switch statements, which can get quite ugly and convoluted, instead encapsulating each separate behavior in separate classes.
4 - Now look to fix up your thread issues. Identify all objects used from multiple threads. Make a list. Now, how are these used? Are some of them always used together? Start making groups. The goal here is to find the level of encapsulation that best works for these objects, separate the objects into individual classes that control their own synchronisation, figure out the atomic level of actual "transactions" for the objects, and make methods of the classes that expose those meaningful transactions, wrapped behind the scenes with the appropriate mutexes, condition variables, etc.
You might be saying "that sounds like a lot of work! Why do all that instead of just writing it all over myself?" Good question! :) The reason is actually straightforward: if you are going to do it all by yourself, those are the steps you should be doing anyway. You should be identifying your states, your dynamic polymorphism, and getting a handle on the multithreaded transactions. But, if you start with the existing code, you also have all of those unspoken business rules that were never documented and may cause all sorts of unexpected bugs down the line. You don't have to bring everything over - if you suspect it's a bug, discuss the logic with the people who have worked with the system in the past (if available), QA, or whoever might identify bugs, and see if it really should be carried over. But you need to actually evaluate what the bugs are either way, or you may not code something that actually needed coding.
In the end, this is a manual process that is a part of software engineering. There are CASE tools that can help draw up the state diagrams and even publish them to code, there are refactoring tools, like those found in many IDEs, that can help move code between functions and classes, and similar tools which can help identify threading needs. However, those things shouldn't be picked up for a single project. They need to be learned throughout your career, picking them up and learning them more deeply over years of work, as they are a part of being a software engineer. They don't do it for you. You still need to know the whys and hows, and they just help get it done more efficiently.
Statecharts (including nested Statecharts) are a powerful way to specify, understand and even simulate/validate complex control flow. But to gain the benefit, you need the statechart model in a suitable tool (I used Statemate way back in the day, not sure if it's still available), plus a reliable mapping from the chart to the code (Statemate used to generate the code) - then you can forget about the state management code (mostly)! In your situation, if you don't have the model, I would try to reverse one from the code - as Ira says, chances are high that the original developers had a model in some form, and you may find the code making a lot of sense as the model emerges. If this works out, you will have a really good spec/model of the code which should make future code edits much easier (even if you don't want to go to automatic code generation, and maintain the code/model mapping manually (but you'll need to be meticulous!!))
Sounds to me like your best bet is (gulp!) likely to start from scratch if it's as horrifically broken as you make out. Is there any documentation? Could you begin to build some saner software based on the docs?
If a complete re-write isn't an option (and they never are in my experience) I'd try some of the following:
If you don't already have it, draw an architectural picture of the whole system. Sketch out how all the bits are supposed to work together and that will help you break the system down into potentially manageable / testable parts.
Do you have any kind of requirements or testing plan in place? If not, can you write one and start to put unit tests in place for the various chunks of code / functionality which exist already? If you can do that, you can start to refactor things without breaking as much of whatever does currently work.
Once you've broken things down a bit, start building your unit tests into integration tests which pull together more of the functionality.
I've not read them myself, but I've heard good things about these books which may have some advice you can use:
Refactoring: Improving the Design of Existing Code (Object Technology Series).
Working Effectively with Legacy Code (Robert C. Martin)
Good luck! :-)

C++ and modularity: Where am I supposed to draw the line?

According to widely spread advice, I should watch out to keep my larger software projects as modular as possible. There are of course various ways to achieve this, but I think that there is no way around to using more or less many interface classes.
Take, as an example the development of a 2D game engine in C++.
Now, one could of course achieve a very modular system by using interfaces for practically everything: From the renderer (Interface Renderer Class -> Dummy, OpenGL, DirectX, SDL, etc.), over audio to input management.
Then, there is the option of making extensive usage of messaging systems, for example. But logically these again come with a high price in performance.
How am I supposed to build a working engine like this?
I don't want to lower the limits for my engine in terms of performance (maximum viable amount of entities, particles, and so on) just to have a perfectly modular system working in the background. This matters because I'd also like to target mobile platforms where CPU power and memory are limited.
Having an interface for the renderer class, for example, would involve virtual function calls for time-critical drawing operations. This alone would slow the engine down by a fair amount.
And here come my main questions:
Where am I supposed to draw the line between consistency and performance with modular programming?
What ways are there to keep projects modular, while retaining good performance for time-critical operations?
There are many ways to keep your code modular without using a single "interface" class.
You already mentioned message passing
then there's plain old callbacks. If an object needs to be able to trigger some event elsewhere in your system, give it a callback function it can invoke to trigger that event. It doesn't need to know anything about the rest of your architecture then
and using templates and static polymorphism, you can achieve most of the same goals as you would with interface classes -- but with zero performance overhead. (For example, template your game engine so that a Direct3D or OpenGL-based renderer can be picked at compile-time)
Moreover, modularity is tricky, and it's not something you get just by hiding everything behind an interface. For it to be modular, whatever that interface implements should be replaceable. You have to have a strategy for replacing one implementation with another. And it has to be possible to create multiple different implementations.
And if you just blindly hide everything behind interfaces, your code will not be modular at all. Replacing any implementation of anything will be such a huge pain, because of the countless layers of interfaces you have to dig through to do so. You'll have to go through hundreds of places in the code and make sure that the right implementation is picked and instantiated and passed through. And your interfaces will be so general that they can't express the functionality you need, or so specific that no other implementation can be made.
If you want a cheesy analogy, bricks are modular. A brick can be easily taken out and replaced with another. But you can also grind them up into tiny particles of baked clay. Is that more modular? You've certainly created more, and smaller "modules". But the only effect is to make it much much harder to replace any given component. I can no longer just pick up one tangible brick, throw it away, and replace it with something else that's brick-sized. Instead, I have to go through thousands of small particles, finding an appropriate replacement for each. And because the replaced component is no longer surrounded by a couple of bricks in the larger structure, but with tens or hundreds of thousands of particles, a ridiculous number of other "modules" are now affected because I swapped out their neighbors that they interfaced with.
Grinding everything up into finer and smaller bits doesn't make anything more modular. It just removes all the structure from your application. The way to write modular software is to actually think and determine which components are so logically isolated and distinct that they can be replaced without affecting the rest of the application. And then write the application, and the component, to maintain this isolation.
Prototype first, then let the interface boundaries emerge.
Preemptive interface design can make coding a drag
Trying to engineer abstraction barriers before you code can be tricky, as you run two risks. One is that you'll inevitably draw some abstraction barriers in the wrong places, and as you start writing working code (as opposed to interface code), you find that your interfaces serve your problem poorly, despite sounding good when described in natural language. The other problem is that it makes coding more of a drag, since you have to juggle two concerns in your head instead of one: writing working code for a problem that you don't completely understand yet, and adhering to an interface that may turn out to be bad.
Interface boundaries emerge from working code.
I am of course not saying that interfaces are bad, but that they're hard to design correctly without having written working code first. Once you have a working program, it becomes obvious which parts should be different instantiations of the same virtual function, which functions need to share resources (and therefore should be put in the same class), etc.
Prototype, then draw only the interface boundaries you need.
I therefore agree with #jdv-Jan de Vaan's suggestion that the first thing to do is to blast out the shortest readable program that works. (This is different from the shortest program that works. There is of course some minimal amount of interface design even at the very beginning.) My addition is to say interface design comes after that. That is, once you have the simple-as-possible code, you can refactor it into interfaces to make it even shorter and more readable. If you want interfaces for portability, I wouldn't start that until you actually have code for two or more platforms. Then the interface boundaries will emerge in a natural (and testable) manner, as it becomes clear which functions can be used as-is for both, and which need to have multiple implementations hidden behind interfaces.
I don't agree with this advice(or maybe your interpretation). "As modular as possible": Where should this end? Are you going to write a virtual interface for 3d vectors, so you can switch implementations? I don't thinks so, but it would be "as modular as possible".
If you are selling a game engine, modularization can help to keep your build times lower, to reduce the amount of header files needed by your prospective clients, and the ability to switch implementations for a particular problem domain (such as directx vs opengl). It can also help to make your code maintaible by partitioning it. But in that case you're not required to decouple the modules with interfaces.
My advice is to always write the shortest readable program that works. If you have can write 20 lines of code that solve some problem locally, or scatter the function over five different classes, the latter would be more modular, but usually the result is less reliable, less readable and less maintainable.
Keep in mind that virtual function calls are intended primarily to deal with a collection of (pointers/references to) objects that aren't necessarily all of the same actual type.
You certainly should not even contemplate something like squares being drawn via OpenGL, but circles via DirectX, or anything on that order. It's perfectly reasonable to handle modularity at this level via templates or even file selection when you build your code, but virtual functions for this situation make no real sense.
That probably brings up the relevant piece of advice for getting performance out of C++: use templates for flexibility and modularity while still retaining maximum performance. One of the main reasons templates are so popular is that they give you modularity without sacrificing performance. The CRTP is particularly relevant to code that may initially seem like it needs virtual functions.
As far as where to draw the line between consistency and performance, there really is no one answer -- it depends heavily on how much performance you need. For your situation (3D game engine for mobile devices) performance is clearly a lot more critical than for many (most) other situations.

How should I design a mechanism in C++ to manage relatively generic entities within a simulation?

I would like to start my question by stating that this is a C++ design question, more then anything, limiting the scope of the discussion to what is accomplishable in that language.
Let us pretend that I am working on a vehicle simulator that is intended to model modern highway systems. As part of this simulation, entities will be interacting with each other to avoid accidents, stop at stop lights and perhaps eventually even model traffic enforcement with radar guns and subsequent exciting high speed chases.
Being a spatial simulation written in C++, it seems like it would be ideal to start with some kind of Vehicle hierarchy, with cars and trucks deriving from some common base class. However, a common problem I have run in to is that such a hierarchy is usually very rigidly defined, and introducing unexpected changes - modeling a boat for instance - tends to introduce unexpected complexity that tends to grow over time into something quite unwieldy.
This simple aproach seems to suffer from a combinatoric explosion of classes. Imagine if I created a MoveOnWater interface and a MoveOnGround interface, and used them to define Car and Boat. Then lets say I add RadarEquipment. Now I have to do something like add the classes RadarBoat and RadarCar. Adding more capabilities using this approach and the whole thing rapidly becomes quite unreasonable.
One approach I have been investigating to address this inflexibility issue is to do away with the inheritance hierarchy all together. Instead of trying to come up with a type safe way to define everything that could ever be in this simulation, I defined one class - I will call it 'Entity' - and the capabilities that make up an entity - can it drive, can it fly, can it use radar - are all created as interfaces and added to a kind of capability list that the Entity class contains. At runtime, the proper capabilities are created and attached to the entity and functions that want to use these interfaced must first query the entity object and check for there existence. This approach seems to be the most obvious alternative, and is working well for the time being. I, however, worry about the maintenance issues that this approach will have. Effectively any arbitrary thing can be added, and there is no single location in which all possible capabilities are defined. Its not a problem currently, when the total number of things is quite small, but I worry that it might be a problem when someone else starts trying to use and modify the code.
As one potential alternative, I pondered using the template system to achieve type safe while keeping the same kind of flexibility. I imagine I could create entities that inherited whatever combination of interfaces I wanted. Using these objects would entail creating a template class or function that used any combination of the interfaces. One example might be the simple move on road using just the MoveOnRoad interface, whereas more complex logic, like a "high speed freeway chase", could use methods from both MoveOnRoad and Radar interfaces.
Of course making this approach usable mandates the use of boost concept check just to make debugging feasible. Also, this approach has the unfortunate side effect of making "optional" interfaces all but impossible. It is not simple to write a function that can have logic to do one thing if the entity has a RadarEquipment interface, and do something else if it doesn't. In this regard, type safety is somewhat of a curse. I think some trickery with boost any may be able to pull it off, but I haven't figured out how to make that work and it seems like way to much complexity for what I am trying to achieve.
Thus, we are left with the dynamic "list of capabilities" and achieving the goal of having decision logic that drives behavior based on what the entity is capable of becomes trivial.
Now, with that background in mind, I am open to any design gurus telling me where I err'd in my reasoning. I am eager to learn of a design pattern or idiom that is commonly used to address this issue, and the sort of tradeoffs I will have to make.
I also want to mention that I have been contemplating perhaps an even more random design. Even though I my gut tells me that this should be designed as a high performance C++ simulation, a part of me wants to do away with the Entity class and object-orientated foo all together and uses a relational model to define all of these entity states. My initial thought is to treat entities as an in memory database and use procedural query logic to read and write the various state information, with the necessary behavior logic that drives these queries written in C++. I am somewhat concerned about performance, although it would not surprise me if that was a non-issue. I am perhaps more concerned about what maintenance issues and additional complexity this would introduce, as opposed to the relatively simple list-of-capabilities approach.
Encapsulate what varies and Prefer object composition to inheritance, are the two OOAD principles at work here.
Check out the Bridge Design pattern. I visualize Vehicle abstraction as one thing that varies, and the other aspect that varies is the "Medium". Boat/Bus/Car are all Vehicle abstractions, while Water/Road/Rail are all Mediums.
I believe that in such a mechanism, there may be no need to maintain any capability. For example, if a Bus cannot move on Water, such a behavior can be modelled by a NOP behavior in the Vehicle Abstraction.
Use the Bridge pattern when
you want to avoid a permanent binding
between an abstraction and its
implementation. This might be the
case, for example, when the
implementation must be selected or
switched at run-time.
both the abstractions and their
implementations should be extensible
by subclassing. In this case, the
Bridge pattern lets you combine the
different abstractions and
implementations and extend them
independently.
changes in the implementation of an
abstraction should have no impact on
clients; that is, their code should
not have to be recompiled.
Now, with that background in mind, I am open to any design gurus telling me where I err'd in my reasoning.
You may be erring in using C++ to define a system for which you as yet have no need/no requirements:
This approach seems to be the most
obvious alternative, and is working
well for the time being. I, however,
worry about the maintenance issues
that this approach will have.
Effectively any arbitrary thing can be
added, and there is no single location
in which all possible capabilities are
defined. Its not a problem currently,
when the total number of things is
quite small, but I worry that it might
be a problem when someone else starts
trying to use and modify the code.
Maybe you should be considering principles like YAGNI as opposed to BDUF.
Some of my personal favourites are from Systemantics:
"15. A complex system that works is invariably found to have evolved from a simple system that works"
"16. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over, beginning with a working simple system."
You're also worring about performance, when you have no defined performance requirements, and no problems with performance:
I am somewhat concerned about
performance, although it would not
surprise me if that was a non-issue.
Also, I hope you know about double-dispatch, which might be useful for implementing anything-to-anything interactions (it's described in some detail in More Effective C++ by Scott Meyers).