Этот вопрос тесно связан с аспектно-ориентированным программированием . AspectJ - это AOP-расширение Java, и вы можете взглянуть на него, чтобы получить некоторое вдохновение.
Насколько мне известно, в Java нет прямой поддержки АОП. Есть несколько шаблонов GOF, которые относятся к нему, например, шаблонный метод и стратегия, но на самом деле это не спасет вам строки кода.
В Java и большинстве других языков вы можете определить повторяющуюся логику, которая вам нужна в функциях, и принять так называемый дисциплинированный подход к кодированию, при котором вы вызываете их в нужное время.
public void checkBalance() {
checkSomePrecondition();
...
checkSomePostcondition();
}
Однако это не подошло бы к вашему случаю, потому что вы хотели бы, чтобы вычеркнутый код мог вернуться из checkBalance
. В языках, поддерживающих макросы (например, C / C ++), вы можете определить checkSomePrecondition
и checkSomePostcondition
как макросы, и они будут просто заменены препроцессором до того, как компилятор даже будет вызван:
#define checkSomePrecondition \
if (!fooIsEnabled) return;
В Java этого нет из коробки. Это может кого-то обидеть, но в прошлом я использовал автоматическое создание кода и механизмы шаблонов для автоматизации повторяющихся задач кодирования. Если вы обрабатываете свои файлы Java перед их компиляцией с помощью подходящего препроцессора, например Jinja2, вы можете сделать что-то похожее на то, что возможно в C.
Возможный подход на чистом Java
Если вы ищете решение на чистом Java, то, возможно, вы найдете не очень лаконичным. Но при этом можно исключить общие части вашей программы и избежать дублирования кода и ошибок. Вы могли бы сделать что-то вроде этого (это своего рода шаблон, вдохновленный Стратегией ). Обратите внимание, что в C # и Java 8, а также на других языках, в которых функции немного проще обрабатывать, этот подход может действительно хорошо выглядеть.
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");
}
});
}
}
Что-то вроде реального сценария
Вы разрабатываете класс для отправки фреймов данных промышленному роботу. Роботу требуется время, чтобы выполнить команду. Как только команда будет завершена, она отправит вам контрольный кадр обратно. Робот может быть поврежден, если он получит новую команду, когда предыдущая все еще выполняется. Ваша программа использует DataLink
класс для отправки и получения кадров от робота. Вам необходимо защитить доступ к DataLink
экземпляру.
Пользовательский интерфейс нить вызовы RobotController.left
, right
, up
или down
когда пользователь нажимает на кнопки, но и вызовы BaseController.tick
через регулярные промежутки времени, для того , чтобы экспедирования повторного включения команды в частном DataLink
случае.
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();
if (frame != null && ) {
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();
}});
}
public void right(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write();
}});
}
public void up(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write();
}});
}
public void down(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write();
}});
}
}