W przypadku, gdy mogą swobodnie korzystać rozszerzenie zamiast realizacji, to można to zrobić w ten sposób:
public interface Thing { ... }
public abstract class Copyable {
public final Copyable copy() {
Copyable clone = createCopy();
if (clone.getClass() != getClass())
throw new RuntimeException("Copy has wrong type!");
return clone;
}
protected abstract Copyable createCopy();
}
a następnie użyć go lubię:
public class Test extends Copyable implements Thing {
public String content = null;
@Override
public Copyable createCopy() {
Test clone = new Test();
clone.content = this.content;
return clone;
}
}
/*code somewhere*/ {
Test t1 = new Test();
t1.content = "Hello world!";
Test t2 = (Test)t1.copy();
System.out.println(t2.content);
}
Jeden problem z tym jest że Copyable
nie jest interfejsem. Można to jednak zastosować bez większego bólu, jak widać w przykładzie, ale sprawdzanie klasy nie jest obsługiwane na poziomie języka. Innymi słowy, metoda abstrakcyjna createCopy
nie jest ograniczona do klasy, którą kopiuje, a wszystko to zależy od programisty, który rozszerza klasę Copyable
lub klasę, która ją rozszerza.
Pozytywną stroną jest to, że jeśli wywołujemy obiekt .copy()
, musi on zwrócić obiekt taki sam jak on. Zamiast wyjątku możesz zwrócić null
, jeśli chcesz. Wtedy masz dobre lub nic.
Ale szczerze mówiąc, tak naprawdę nie rozumiem, dlaczego lokalna metoda ma parametr. To może być następnie metoda statyczna ... altrough nie mogę sobie nawet wyobrazić, co by przejść do tego bloku kodu:
static <X extends Thing> X copy(X object) { ... }
Może można połączyć Practice ze statycznej metody rodzajowe i wynik staje się nieco bardziej przyjazny :
public interface Thing extends Cloneable {
public static <X extends Thing> X copy(X thing) {
Object clone = thing.clone();
if (clone.getClass() != getClass())
throw new RuntimeException("Copy has wrong type!");
return (X)clone;
}
}
public class ThingA implements Thing {
public Object clone() { ... }
}
/*code somewhere*/ {
ThingA a1 = new ThingA();
ThingA a2 = Thing.copy(a1);
}
Mimo to, metoda klonowania jest regulowany przez wyjątek zamiast ograniczenia języka, ale myślę, że jest to zdecydowanie najlepsze rozwiązanie.
To nadal pozwala mu robić dokładnie to, czego nie chce. Generics nie zapobiega używaniu tylko jednego rodzaju klasy, ponieważ będzie to całkowite przeciwieństwo celu generycznego. – giorashc