Identify implementations of base class in an array
Asked Answered
H

1

7

I have the following problem: I have a set of engines which automaticly (listening to events) controls my model. The following picture shows in general the class diagram: Class Diagramm

Now I have a client which knows the EngineFacade and i want to set the property Active from Engine2 from the client, but neither the client nor the EngineFacade knows which of the three engines is Engine2.

There are two ways, but I dont like any of them:

  1. Check if one of the engines is of type Engine2 - if there is another class which does the same task but is named different I have to change it in the EngineBuilder AND in the EngineFacade.
  2. Check with an identifier string - I dont really like magic strings.

What I know on the client site is that there is or should be an engine which handels the grid. But I dont know more.

Maybe I have to choose between the two devils, but maybe one of you has a better solution.

Hiss answered 7/3, 2013 at 14:51 Comment(7)
If you have to identify every engine separately, easy option is to give it a unique identifier. Another way to do it is to have a name property on the base engine. Every engine implements the name property and then fire an event and then examine the sender parameter.Resnick
Perhaps you should examine the abstraction provided by the facade. Sounds like you have some leakage.Mow
You might want to include the client, its methods and its variables in your diagram, or post some code illustrating usage.Aretta
If Engine2 is more specialized than both Engine1 and Engine 3, then de facto it is implementing an additional service contract ISpecificToEngine2. Explicitly defining and exposing this additional service contract would allow all engines implementing this additonal contract to be selected by clients.Drypoint
Engine2 is not special to Engine1 or 3. Lets say Engine1 check cllision, Engine2 checks if everything fits into a grid and Engine3 syncs stuff to the view. I only want to have the ability to deactivate the Engine2 with the property defined in the EngineBase.Hiss
@Yggdrasil: Your abstraction model is no longer reflecting your business requirments accurately. If this is an isolated case, live with it; but if it is just the tip of an impending iceberg, resolve it now before it sinks you.Drypoint
@PieterGeerkens: I really liked the idea of engines which do their work "under the surface". I have not really an idea how to lift this iceberg. The application is based on transactions. The engines react on these transaction and do checks and things like rearrangement...Hiss
P
1

You could use an attribute on the implementation of Engine2, like so:

[AttributeUsage(AttributeTargets.Class)]
public class HandlesGridAttribute : Attribute { }

Which you then apply to your derivation:

[HandlesGrid]
public Engine2 : EngineBase { ... }

Then, in your client, check for the attribute:

IEnumerable<EngineBase> bases = ...;

// Get all the implementations which handle the grid.
IEnumerable<EngineBase> handlesGrid = bases.
    Where(b => b.GetType().
        GetCustomAttributes(typeof(HandlesGridAttribute), true).Any());

// Set the active property.
foreach (EngineBase b in handlesGrid) b.Active = true;

The major drawback here (which may or may not apply to you) is that you can't change the value at runtime (since the attribute is baked in at compile time). If your engine is not dynamic in this way, then the attribute is the right way to go.

If you need to change whether or not a derivation can perform this action at runtime though, then you have to fall back to your second option, code constructs that identify what the attributes of the engine are. Mind you, it doesn't have to be a string (and I don't like that either), but it can be something that is more structured that will give you the information you're looking for.

Poulard answered 8/3, 2013 at 14:51 Comment(2)
Thx, this was what I was looking for. I only have to check how performant this is.Hiss
It seems that it is not so expensive. Just in case I cach this engine where I use it.Hiss

© 2022 - 2024 — McMap. All rights reserved.