以下のアプローチについてはどうですか(単純な継承とジェネリックメソッド):
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class XmlTest {
@Test
public void test() {
XMLFirstSubclass url = new XMLFirstSubclass("url");
XMLSecondSubclass xmlSecondSubclassInstance = new XMLSecondSubclass(
"loc").add("http://goout.cz").appendTo(url);
}
}
abstract class XML {
private final List<String> texts = new ArrayList<String>();
private final List<XML> nodes = new ArrayList<XML>();
private final String nodeName;
protected XML(String nodeName) {
this.nodeName = nodeName;
}
@SuppressWarnings("unchecked")
public <R extends XML> R add(String text) {
texts.add(text);
return (R) this;
}
@SuppressWarnings("unchecked")
public <R extends XML, T extends XML> R add(T node) {
nodes.add(node);
return (R) this;
}
@SuppressWarnings("unchecked")
public <R extends XML, T extends XML> R appendTo(T node) {
node.add(this);
return (R) this;
}
}
class XMLFirstSubclass extends XML {
public XMLFirstSubclass(String nodeName) {
super(nodeName);
}
}
class XMLSecondSubclass extends XML {
public XMLSecondSubclass(String nodeName) {
super(nodeName);
}
}
ジェネリック メソッドでは、1 つの型 T からノードを取得し、インスタンスの型 R を返すことができることに注意してください。これは、引数の型とは異なる場合があります。T は R とは異なる場合がありますが、どちらも XML を継承しています。
質問で提示されたアプローチに関するコメント
あなたが今まで使ってきたアプローチは、奇妙な状況につながる可能性があります. これを例で説明しましょう。
以下では、XML を特化した最初のクラスを作成してみます。
public class XMLFirstSubclass extends XML<OtherXMLSubclass> { ... }
最初の XML サブクラスを作成している場合、OtherXMLSubclass に可能な唯一の値は、XMLFirstSubclass であるか、ジェネリック型をまったく宣言しないことです。
最初のオプション:
public class XMLFirstSubclass extends XML<XMLFirstSubclass> { ... }
2番:
public class XMLFirstSubclass extends XML { ... }
クラスの設計でジェネリックを使用することを選択した場合、2 番目のオプションは不適切に思えます。
最初のオプションを詳しく見てみると、次のようなサブクラスを取得する可能性が開かれます。
class XMLSecondSubclass extends XML<XMLFirstSubclass> {
...
}
これは完全にコンパイルされますが、実行時に XMLSecondSubclass メソッド呼び出しでクラス キャスト例外が発生することに注意してください。