tags:

views:

68

answers:

4

I have a class A with a

public String toString() {
}

method.

It gets compiled. Also, I have several implementations of that method as a method body. This implementation uses A's fields.

I want to be able to dynamically substitute the contents of the toString() method with such or such an implementation. The point here is that I need A's fields in the implementation.

I must say, I cannot create subclasses of A. I must use this class only.

As I can guess, each implementation must be compiled before the first usage. But how would one do that?


The simplest solution would probably be to use a flag variable and analyze it before invoking such or such a method or even put everything into toString and use switch. But what if A doesn't know anything about its implementation itself? Can they be decoupled - the A class and its toString implementations?

+1  A: 

I don't get the point of doing so and what you mean exactly by 'dynamically substitute' it, but you could add an additional field to A which you use to switch over the implementations. Something along the following lines. You can then 'dynamically' switch to different implementations by changing this mode variable.

public String toString() {
  switch(mode) {
    case 1: return toStringImplementation1();
    case 2: return toStringImplementation2();
    /* ... */
    default: return super.toString();
  }
}

As to your follow-up question on decoupling: of course, it is possible. However, you said that the implementations directly depend on the fields of A, and you probably don't want to open those to the world. I also don't see any advantage over decoupling the implementations into inner classes, instead of plain methods, but then again I still don't know what you're trying to achieve.

Frank
No, it won't go :)
EugeneP
+2  A: 

I guess in theory you could create multiple classes called A with different implementations of the toString() method, and then dynamically load them with different classloaders, etc. However, from the JVM's perspective they WILL be different classes, and you won't be able to convince the JVM differently. So you won't end up "winning".


A more practical approach might be something like this:

class A {
    Formatter f;
    A(Formatter f) {
        this.f = f;
    }
    ...
    @Override 
    public String toString() {
        return f.format(this);
    }
}

and write lots of classes to implement the Formatter interface.

Stephen C
To me its similar to visitor pattern. Isn't it?
Adeel Ansari
@Vinegar - not really. A Visitor is used to do something on all nodes of some data structure. This more like the Strategy pattern, except that the strategy is wired at object creation time.
Stephen C
+1  A: 

How about using the decorator pattern?

the decorator pattern is a design pattern that allows new/additional behaviour to be added to an existing object dynamicall

(although I'm not sure if this fits with the changes you can or cann't make to A)

Edit: If you can categorically only use A's fields (and not field accessor (getter) methods) then the Decorator pattern probably will not work. It's a little hard to tell from the question if this is the case.

Joel
Strange question, but the decorator is the only solution where A doesn't need to know the implementation of the toString-Method.
Hardcoded
A: 

Is this homework? If so you shoudl tag it as such.

What will provide the best solution depends on what you want to achieve, if you need multiple string representations of the object, you could introduce multiple versions of toString like:

public String toString() {
}

public String toXmlString() {
}

public String toHumanFriendlyString() {
}

If on the other hand you have methods like the above implemented in your object and you want to set the output format you can use an output type:

public String toString() {
    switch (outputType) {
    default:
         return "Unknown output type for: " + toDebugString();
    case TYPE_DEBUG:
         return toDebugString();
    case TYPE_XML:
         return toXmlString();

}

If you need implementation to be settable from other parts of your code can use a plugin pattern:

interface Stringable {
    String toString(A a);
}

class A {

    Stringable impl = this;

    void setStringable(Stringable s) {
         impl = s;
    }

    String toString() {
         return impl.toString(this);
    }

    String toString(A a) {

          return "A a";
    }
}
rsp