Re: Objekt 'einfrieren'?
- From: "Paul Ebermann" <Paul-Ebermann@xxxxxx>
- Date: Sat, 10 Nov 2007 23:43:15 +0100
"Ivan Dolvich" skribis:
[viel Code]Gibts da eine möglichkeit das in der Abstrakten Klasse irgendwie
festzulegen, oder geht das nur über den Umweg in alle Unterklassen rein
zu gehen und das in die Setter zu implementieren?
Du könntest vielleicht das Objekt durch ein anderes, unveränderliches
ersetzen. Dazu müssten aber alle Zugriffe aufs Objekt nie direkt,
sondern durch einen "Proxy" erfolgen.
Ist etwas kompliziert, aber unserem Pattern-Professor würde es bestimmt
gefallen.
Hmm, den ImmutableFO würde ich weglassen, und stattdessen
in der set-Methode des Proxys ein frozen-Flag abfragen.
(Und außerdem wäre mir eine Exception lieber als einfach
nichts zu tun, aber das geht ja bei dir auch einfach.)
Damit das aber ordentlich funktioniert, sollte man das ganze
generisch machen, mit java.lang.reflect.Proxy.
Hier ein Beispiel.
---
import java.lang.reflect.*;
public interface Freezable {
/**
* Friert das Objekt ein.
*/
public void freeze();
}
/**
* wird von set-Methoden geworfen, wenn das
* entsprechende Objekt eingefroren wird.
*/
public class FrozenException extends RuntimeException {
FrozenException(String message) {
super(message);
}
}
public class Freezer {
/**
* @param interfaceType das Class-Objekt des Interfaces E.
* @param delegate an dieses Objekt werden alle Aufrufe von
* in E deklarierten Methoden des Ergebnis-Objektes
* weitergeleitet, ebenso wie hashcode, toString
* und equals.
*
* @returns ein Objekt, welches neben E auch noch Freezable
* implementiert. Ab dem Aufruf von freeze() funktionieren die
* set-Methoden nicht mehr, alle anderen Methodenaufrufe werden
* aber an delegate weitergeleitet.
*/
public <E> E createFreezable(final Class<E> interfaceType, final E delegate) {
InvocationHandler handler =
new InvocationHandler() {
boolean frozen;
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
String name = method.getName();
if (name.equals("freeze") &&
args.length == 0) {
frozen = true;
return null;
}
if (frozen && name.startsWith("set")) {
throw new FrozenException("Objekt eingefroren, method " + name +
" nicht erlaubt");
}
return method.invoke(delegate, args);
}
};
Object proxy =
Proxy.newProxyInstance(interfaceType.getClassLoader(),
new Class[] { interfaceType, Freezable.class },
handler);
return interfaceType.cast(proxy);
}
}
class Test {
public static void main(String[] egal) {
// zum Testen nehme ich mal das Interface und
// die MutableFO-Klasse von Ivan
x1 = new X(42);
x2 = new X(13);
FreezyObject fo =
new Freezer().createFreezable(FreezyObject.class, new MutableFO());
fo.setX(x1); // OK
// einfrieren:
((Freezable)fo).freeze();
try {
fo.setX(x2); // gibt eine Exception
}
catch (FrozenException ex) {
ex.printStackTrace();
}
// get geht aber:
System.out.println(fo.getX());
}
}
---
(Nicht ausprobiert, eventuell müssen noch ein paar
Syntax(tipp)fehler behoben werden.)
Leider gibt es in Java keine Schnittmengen-Typen,
so dass die Signatur von createFreezable sagen könnte,
dass das Ergebnis-Objekt auch Freezable ist - dadurch
müssen wir zum Einfrieren auf Freezable casten.
Falls man keine Exception will, kann man in der
entsprechenden Zeile auch einfach ein "return null;"
machen.
Das ganze geht natürlich daneben, wenn sich das Objekt
noch über andere Methoden als solche, deren Namen mit
"set" beginnt, ändern lässt - dies ist etwa bei ziemlich
allen Interfaces in java.util der Fall (sofern es
überhaupt etwas zu ändern gibt).
Paul
--
Eine Signatur sollte mit "-- " abgetrennt werden,
wobei OjE meist das " " verschluckt. Eine nicht
korrekt abgetrennte Signatur ist keine Signatur ...
.
- References:
- Re: Objekt 'einfrieren'?
- From: Ivan Dolvich
- Re: Objekt 'einfrieren'?
- Prev by Date: Re: Objekt 'einfrieren'?
- Next by Date: Re: Wie lassen sich UTF-8 Dateien einlesen ???
- Previous by thread: Re: Objekt 'einfrieren'?
- Next by thread: Wie lassen sich UTF-8 Dateien einlesen ???
- Index(es):
Relevant Pages
|