http://maoe.hatenadiary.jp/entry/20101214/1292337923
Wie kann ich neue Datentypen oder neue Funktionen in einer statisch typisierten Sprache hinzufügen, ohne sie neu zu kompilieren?
Ist das Problem. Wenn Sie eine Klasse ohne nachzudenken entwerfen,
Haskell, OCaml, Scala usw. sind bereits für Lösungen mit erweiterten Sprachfunktionen (?) Berühmt. Es wird jedoch gezeigt, dass das Ausdrucksproblem auch mit Java-Sprachfunktionen gelöst werden kann.
Es gibt die beiden oben genannten Methoden. Dieser Artikel stellt zwei Methoden vor.
Betrachten Sie zunächst einen einfachen Interpreter als Beispiel. Beachten Sie, dass Lombok zur Vereinfachung des Codes verwendet wird.
import lombok.AllArgsConstructor;
import lombok.Data;
interface Exp {
int eval();
}
@Data
@AllArgsConstructor
class Add<E extends Exp> implements Exp {
private E e1;
private E e2;
@Override
public int eval() {
return e1.eval() + e2.eval();
}
}
@Data
@AllArgsConstructor
class Lit implements Exp {
private int x;
@Override
public int eval() {
return x;
}
}
Die Stelle, an der das Feld der Add-Klasse ein Typparameter namens E ist, ist ein Fehler.
Fügen Sie dieser Klasse einen Druckvorgang hinzu.
interface ExpP extends Exp {
String print();
}
class LitP extends Lit implements ExpP {
LitP(int x) {
super(x);
}
@Override
public String print() {
return String.valueOf(getX());
}
}
class AddP<E extends ExpP> extends Add<E> implements ExpP {
AddP(E e1, E e2) {
super(e1, e2);
}
@Override
public String print() {
return getE1().print() + " + " + getE2().print();
}
}
Ich konnte die vorhandene Klasse problemlos hinzufügen.
Fügen Sie eine Klasse hinzu, die Sub darstellt (Subtraktion).
@Data
@AllArgsConstructor
class Sub<E extends Exp> implements Exp {
private E e1;
private E e2;
@Override
public int eval() {
return e1.eval() - e2.eval();
}
}
class SubP<E extends ExpP> extends Sub<E> implements ExpP {
SubP(E e1, E e2) {
super(e1, e2);
}
@Override
public String print() {
return getE1().print() + " - " + getE2().print();
}
}
In beiden Fällen können Operationen hinzugefügt / Klassen hinzugefügt werden, ohne die vorhandene Klasse zu ändern. Die Klasse, die diese verwendet, ist wie folgt.
public class Main {
public static void main(String[] args) {
new Add<Exp>(new Lit(1), new Lit(3)).eval();
new Sub<Exp>(new Lit(1), new Lit(3)).eval();
new AddP<ExpP>(new LitP(1), new LitP(3)).print();
new SubP<ExpP>(new LitP(1), new LitP(3)).print();
}
}
In Situationen, in denen eine hohe Erweiterbarkeit erforderlich ist (von denen erwartet wird, dass sie sowohl die Datenstruktur als auch den Betrieb erweitern), lohnt es sich, sich an dieses Entwurfsmuster zu erinnern (unbekannter Name?). Wenn Sie sich auch für die Methode "Verwenden von Subtypisierung + Kovariation des Rückgabewerts" interessieren, lesen Sie bitte die folgenden Referenzen. (* Der Inhalt dieses Artikels ist das runde Pakuri des folgenden Papiers.)
Recommended Posts