Diese Frage steht in engem Zusammenhang mit der aspektorientierten Programmierung . AspectJ ist eine AOP-Erweiterung von Java, und Sie können einen Blick darauf werfen, um etwas Inspiration zu erhalten.
Soweit ich weiß, gibt es in Java keine direkte Unterstützung für AOP. Es gibt einige GOF-Muster, die sich darauf beziehen, wie zum Beispiel Vorlagenmethode und Strategie, aber es werden Sie nicht wirklich Codezeilen speichern.
In Java und den meisten anderen Sprachen können Sie die wiederkehrende Logik definieren, die Sie in Funktionen benötigen, und einen sogenannten disziplinierten Codierungsansatz anwenden, bei dem Sie sie zum richtigen Zeitpunkt aufrufen.
public void checkBalance() {
checkSomePrecondition();
...
checkSomePostcondition();
}
Dies würde jedoch nicht zu Ihrem Fall passen, da Sie möchten, dass der ausgerechnete Code zurückgegeben werden kann checkBalance
. In Sprachen, die Makros unterstützen (wie C / C ++), können Sie diese als Makros definieren checkSomePrecondition
und checkSomePostcondition
sie werden einfach durch den Präprozessor ersetzt, bevor der Compiler überhaupt aufgerufen wird:
#define checkSomePrecondition \
if (!fooIsEnabled) return;
Java hat dies nicht sofort einsatzbereit. Dies mag jemanden beleidigen, aber ich habe in der Vergangenheit automatische Codegenerierungs- und Vorlagen-Engines verwendet, um sich wiederholende Codierungsaufgaben zu automatisieren. Wenn Sie Ihre Java-Dateien verarbeiten, bevor Sie sie mit einem geeigneten Präprozessor kompilieren, z. B. Jinja2, können Sie etwas Ähnliches tun, wie es in C möglich ist.
Möglicher reiner Java-Ansatz
Wenn Sie nach einer reinen Java-Lösung suchen, wird das, was Sie möglicherweise finden, wahrscheinlich nicht präzise sein. Es könnte jedoch weiterhin allgemeine Teile Ihres Programms herausrechnen und Codeduplikationen und Fehler vermeiden. Sie könnten so etwas tun (es ist eine Art Strategie- inspiriertes Muster). Beachten Sie, dass dieser Ansatz in C # und Java 8 sowie in anderen Sprachen, in denen Funktionen etwas einfacher zu handhaben sind, möglicherweise tatsächlich gut aussieht.
public interface Code {
void execute();
}
...
public class Foo {
private bool fooIsEnabled;
private void protect(Code c) {
if (!fooIsEnabled) return;
c.execute();
}
public void bar() {
protect(new Code {
public void execute() {
System.out.println("bar");
}
});
}
public void baz() {
protect(new Code {
public void execute() {
System.out.println("baz");
}
});
}
public void bat() {
protect(new Code {
public void execute() {
System.out.println("bat");
}
});
}
}
Ein bisschen wie ein reales Szenario
Sie entwickeln eine Klasse zum Senden von Datenrahmen an einen Industrieroboter. Der Roboter braucht Zeit, um einen Befehl auszuführen. Sobald der Befehl abgeschlossen ist, sendet er Ihnen einen Kontrollrahmen zurück. Der Roboter kann beschädigt werden, wenn er einen neuen Befehl erhält, während der vorherige noch ausgeführt wird. Ihr Programm verwendet eine DataLink
Klasse zum Senden und Empfangen von Frames zum und vom Roboter. Sie müssen den Zugriff auf die DataLink
Instanz schützen .
Die Benutzeroberfläche Thread Anrufe RobotController.left
, right
, up
oder , down
wenn der Benutzer klickt auf die Tasten, sondern ruft auch BaseController.tick
in regelmäßigen Abständen, um zu reaktivieren Befehlsweiterleitung an die privaten DataLink
Instanz.
interface Code {
void ready(DataLink dataLink);
}
class BaseController {
private DataLink mDataLink;
private boolean mReady = false;
private Queue<Code> mEnqueued = new LinkedList<Code>();
public BaseController(DataLink dl) {
mDataLink = dl;
}
protected void protect(Code c) {
if (mReady) {
mReady = false;
c.ready(mDataLink);
}
else {
mEnqueue.add(c);
}
}
public void tick() {
byte[] frame = mDataLink.readWithTimeout(/* Not more than 50 ms */);
if (frame != null && /* Check that it's an ACK frame */) {
if (mEnqueued.isEmpty()) {
mReady = true;
}
else {
Code c = mEnqueued.remove();
c.ready(mDataLink);
}
}
}
}
class RobotController extends BaseController {
public void left(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'left' by amount */);
}});
}
public void right(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'right' by amount */);
}});
}
public void up(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'up' by amount */);
}});
}
public void down(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'down' by amount */);
}});
}
}