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?
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.
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.
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.
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";
}
}
精彩评论