views:

484

answers:

7

I'm not quite sure how to explain this (that's why the title is kinda weird) but I'll have a go. Basically I'm doing some Oject-Oriented Design and I want to represent various different types of object, each of which can have various actions which it can perform. An example might help: things such as a File which can have delete, rename and open actions and an Application which can have run, close, uninstall and move to other monitor actions.

My first thought was to use an interface (IAction) and have all my classes for the different types of objects implement that interface, but that won't work as each object will have different methods which the inteface won't know about this.

The question then arises of how, if they all have different methods, the methods will actually get called - because at runtime it will be impossible to know which objects have which methods. That's another problem - I'd like each object to be able to produce a list of the methods it has, and then let me call any of them.

Does this need to be done with reflection? I'm pretty sure it can't be done with standard interfaces - but I'm a bit new to all this OOP design so I'm not entirely sure.

+7  A: 

Robin - I'm assuming that you are doing this with an eye toward offering a "generic" interface to these objects for your users. I did something similar in an earlier project and documented the UI that I ended up with in an answer I posted earlier.

To answer your specific question, you should be a bit careful here as you might be entering Architecture Astronaut territory (not a good thing). If the interfaces for each of your objects don't naturally overlap, forcing them to share a conceptual interface via odd machinations will just end up confusing your users. You can solve this problem by implementing Interfaces that call the "closest enough" function for very broad conceptual categories (e.g. files and applications are both "Opened" but the result is different for each). You can also use reflection to discover more about your objects at the point where you need to display the options available. Thus, you can do it. The question is, should you do it?

Mark Brittingham
Or, in other words, the question is "What should you do?" (i.e. what's the purpose of the application you're willing to build with that 'File' and 'Application' classes).
mlvljr
A: 

Reflection can certainly tell you which methods an object has at execution time.

How is anything going to cal any of these methods? By reflection, based on name?

Jon Skeet
+2  A: 
public interface IDiscoverableAction {
    string Name { get; }
    void Execute();
}

public interface IHasDiscoverableActions {
   IEnumerable<IDiscoverableAction> DiscoverActions();
}
Justice
I know this is self-explanatory to some, but you're talking to a bunch of humans, not a computer, and a little explanation beyond code might help.
Jon Limjap
I am not writing for a general audience of humans. I am writing only for those humans somewhat fluent in computer programming, object-oriented design, and C#. Those five lines of code either should be self-explanatory, given the context of the OP's question, or should never have been written.
Justice
+2  A: 

I agree with Mark's warning to think long and hard about why you need to be doing this. Calling methods/actions whose identities are not known until runtime just strikes me as a Bad Idea.

But if you must, here's another thought: make your IAction interface with a getActions() method which returns a list of function pointers or something. If you don't have any equivalent to function pointers in your language, have getActions() return a list of strings and add a callAction(string) method to the IAction interface, which each class implements to call the appropriate method based on the parameter. It might be a little bit faster than using a builtin reflection mechanism.

David Zaslavsky
A: 

The problem with executing methods via reflection is that you really have no idea what you are executing. You can reflect and discover that you have a move method but what does that move method do? If there are parameters to that method, you can discover those as well, but from the names of the parameters are you going to have some sort of AI that determines what each parameter name means?

If you can't find enough commonality between these objects that they can share an interface then they are really in no way related and shouldn't be forced to.

Perhaps there are cases where unrelated classes might have one or two things in common. In this case you might try to define an interface to identify this. Ex: ISupportsDelete. Dealing with things at this granular level is the only way you are going to be able to treat unrelated objects like this in any type of generic fashion.

Jim Petkus
A: 

What I am imagining is that you wish to build a sort of execution context or engine and that these objects that are being utilized by the engine need to be generically passed into the engine. Once the engine takes hold of the object, the engine then needs to figure out what to do with the object...

Assuming that this is correct, you can either use inheritance to inherit from a base class, e.g., FrameworkObject, or you can implement a common interface, e.g., IFrameworkObject. You may choose to use the interface as nothing more than a polymorphic "marker" interface. This was required in ActiveX component programming back in the day. I prefer the marker interface, because class inheritance is not something that is trivial, from the perspective of the framework refactoring life cycle, and it can tend to create kludged code due to base class bloat as features are added that some, but not all, derived classes need.

Once you have a generic mechanism, i.e., type container via the interface implementation on each of the classes, you can can use reflection or perhaps simply the "is" operator (in C#) to figure out if a particular object implements a specific interface that pertains to either a File entity or an Application entity, for example.

After you determine the execution context via interface identification (don't kid yourself that you will be able to do this at a method granularity level), the next decision is whether to attempt to use reflection and hard-coded logic to execute various methods. If you want to make it extremely generic, you could rely on metadata that is stored in files or in a database to drive the logic. For example, the execution engine could load the supported interfaces when it starts up and then use reflection to interrogate any object that implements the IFrameworkObject interface.

The more I think about it, the more I feel that your requirements suggest that you are implementing a sort of scripting language and that part of the requirements is to tokenize commands through lexical analysis.

EnocNRoll
A: 

Maybe you have this the wrong way. Should the objects actually implement those actions?

Take File. Isn't more natural to have the FileSystem object implement the delete action?

In any case you could construct a really dynamic system by introducing a few layers of indirection.

Lets say you implement DeleteAction as an UnaryOperation depending on a Deletable.

Adding the DeleteAction to the ActionRepository registers it as available for Deletable objects.

If you want to avoid statically binding File to Deletable you can introduce an AdaptorRepositor where you add a File2Deletable adaptor.

ActionRepository.listActions(Object o) will then give you a list of all actions that is either directly usable with a File or any of the available adaptors of a File.

John Nilsson