2

Here is the scenario: I have an interface A, 100 classes B0 ... B99 that implement only A and 50 classes C0, C2 ... C98 that extend B0, B2 ... B98.

The B classes work with a MySQL database, doing various stuff on the tables. The C classes add extra logic to B classes (validations, privileges etc). The B classes are generated by a tool, while the C classes are written by a coder.

A client application will use the B classes and will not have access to C classes. When a method is called for a B object, the client will serialise the object and send it to a server application, along with the method name that is to be called.

The server will receive the B object and cast it as an A. However, the server would like to execute the method that was overridden in the C class if such a class exists, and the method from B otherwise. Normal behaviour would only execute the method from B.

How would the server be able to do that without having a huge SWITCH statement that would cast the received object to a C?

EDIT: I am new to java and did not know what reflection could do. With a little help from google (this and this) I solved my problem. I can use dynamic casting for what I want to achieve. Thanks to everybody.

Community
  • 1
  • 1
  • Are you saying that your client will do `B b = new B();`, but you want your application to somehow convert `b` to a `C`? – Oliver Charlesworth Apr 13 '11 at 12:06
  • Indeed. The server will receive the object as A obj = Receive() and call the method as obj.someMethod(). How the server decides what method to call is not important (there are only a few methods implemented in all classes). I would like the someMethod() of the C to be called, if C is avaliable. –  Apr 13 '11 at 12:14

3 Answers3

2

That approach sounds really odd to me. Why don't you just provide commands (e.g. strings that define the command names) and register command objects for those commands? Then you just send over the command as well as some serialized parameters.

Edit:

From your description it seems as if the C objects would really be decorators to the B object. In that case they would not inherit from the corresponding B but take e reference to it and the server would then look up the decorators for the B passed (based on class for example, or any other identifier), create them (or just one) passing the B and then invoke the method on the decorator.

Much like BufferedReader decorating any Reader.

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • Even to me the approach seems more than odd ... idiotic maybe :) ? –  Apr 13 '11 at 12:16
  • Well, as I said, I'd just send two parameters (may be packed into one transport object), select the method according to one parameter and the parameters for the method according to the second. – Thomas Apr 13 '11 at 12:20
  • Sorry for the incomplete reply. What I wanted to add was: This approach would be a way to keep the logic code away from the client and still work with the objects transparently; a function call would look like a function call in the client code, even if the object would travel to the server and back. –  Apr 13 '11 at 12:25
2

Assuming that each C class has a constructor or a static createFromSuper to create it from it's parent B (or from an A)...

You can create a FactoryClass where all available C's are registered. You can use reflection to get the parent of C you want to "replace", remembering each B.class->C.class mapping in a Map/Hashtable.

Then when you receive a B, you pass it to the Factory, which will return the same B object if it finds a mapping, or calls the constructor/createFromSuper returning the C.

subsub
  • 1,857
  • 10
  • 21
0

Well you have an object of runtime type B, and you are asking to call it as if it were an object of type C. This isn't really how inheritance works; you cannot downcast to C unless it was originally created as a C, because in general, it doesn't have all the fields of C.

I am guessing your C classes do not add any additional fields to a B (if they did, your question wouldn't make sense). Since they don't add any additional fields, then I can see how it would make sense to treat them as a C, but there isn't a really good way to do it. I would say:

  1. Why are there Bs and Cs in the first place? Why not just have B classes, with all the privileges, etc, and use that?
  2. Failing that, I suppose you could use reflection. Write some generic code that takes any of your B class objects, constructs a new corresponding C object, and copies over all of the fields.
mgiuca
  • 20,958
  • 7
  • 54
  • 70
  • B classes are generated by a tool. If I write additional code and run the tool again, my work will go down the drain. –  Apr 13 '11 at 12:14
  • 1
    You could use a workflow where, when regenerating, you don't overwrite the existing classes, but rather merge with them. If you are careful in how you lay out your code in the class, the merges should be painless. This would preserve your code, but let you add new autogenerated stuff. – Tom Anderson Apr 13 '11 at 12:35
  • Yes, but this would also expose the logic to the client, which I don't really want to do. For example, privileges are checked server side. The code wouldn't even compile. –  Apr 13 '11 at 12:47
  • I guess then you should fall back to reflection (suggestion #2). A few other people have given a bit more detail about how you might do that. – mgiuca Apr 13 '11 at 15:01