Java API Designing проблема при создании собственного API

1

Я работаю над проектом, который включает связь между компьютерным приложением и встроенными устройствами через последовательный порт в режиме Master-Slave.

Приложение будет служить мастером для нескольких встроенных устройств, работающих как подчиненные.

Коммуникационная часть почти завершена. Но теперь я реорганизую его как API. Таким образом, он может использоваться для нескольких проектов или для многих разработчиков с очень небольшими конфигурациями.

Я не очень хорошо разбираюсь в дизайне API, даже в первый раз я создаю API.

Теперь я застрял в следующем выпуске: рассмотрим этот сценарий:

/*
 * API Part
 */
public abstract class AbstractSlave {

  // Some fields, constructor and other methods.

  final void handle(Request request, Response response) {
    // Some operations before starting worker thread.

    SlaveWorker worker = new SlaveWorker(request, response);
    worker.start();
  }

}

public class SlaveWorker extends Thread {

  // Constructor

  @Override
  public final void run() {
    work(request, response);
  }

  public void work(Request request, Response response) {

  }

}

Класс AbstractSlave запускает рабочий поток для работы с запросом и ответом, так что длительные операции не могут вызвать потерю предстоящих ответов от ведомых.

Теперь, вот "часть использования API":

/*
 * API Usage Part
 */
public class Slave extends AbstractSlave {

  // Constructor

}

public class MyWorker extends SlaveWorker {

  // Constructor

  @Override
  public void work(Request request, Response response) {
    super.work(request, response);

    // My work to be done upon request and response.
  }

}

Но, как мы видим, AbstractSlave создает экземпляры SlaveWorker. Таким образом, будет вызван метод SlaveWorker work() вместо MyWorker.

Как сделать класс AbstractSlave для вызова MyWorker work() MyWorker?

ЗАМЕТКА:

  • Как и дизайн API, AbstractSlave не знал бы, есть класс MyWorker. Таким образом, экземпляры MyWorker не могут быть созданы непосредственно вместо SlaveWorker.
  • Метод handle() AbstractSlave может/не может быть переопределен, потому что есть некоторые операции, которые необходимо выполнить перед началом рабочего потока.
Теги:
design-patterns
design
api-design

2 ответа

0
Лучший ответ

Я думаю, что ключевым моментом было бы позволить клиенту вашего API создать экземпляр SlaveWorker (или любого подкласса), чтобы он мог настроить метод work().

IMO вы должны предоставить интерфейс Worker в вашем API (интерфейс менее сдерживает, чем абстрактный класс):

public interface Worker {
    public void work(Request request, Response response);
}

Метод AbstractSlave должен выглядеть следующим образом:

public abstract class AbstractSlave {

    private final Worker worker;

    public AbstractSlave(Worker worker) {
        this.worker = worker;
    }

    final void handle(final Request request, final Response response)
        // Some operations before starting worker thread.

        Thread t = new Thread() {
            public void run() {
                worker.work(request, response);
            }
        };
        t.start();
    }

}
  • 0
    В дизайне вашего метода дескриптора передается рабочий экземпляр. Но опять дескриптор вызывается изнутри API. Как можно передать экземпляр MyWorker?
  • 0
    Как, из вашего второго редактирования. Я думаю так же. Позволить клиенту предоставить экземпляр. Но что будет лучшим способом! Я думаю о создании абстрактного метода getSlaveWorker () в классе AbstractSlave. Как вы думаете, это правильный подход?
Показать ещё 9 комментариев
0

Существуют разные способы сделать это, но один из способов - добавить метод configureJob к вашему AbstractSlave и использовать его, чтобы рассказать класс AbstractSlave о MyWorker.

public class SlaveManager {
   private Class workerClass = SlaveWorker.class;

   public void configureJob(Class clazz){
      workerClass = clazz;
   }

   final void handle(Request request, Response response) {
      // Some operations before starting worker thread.

      Worker worker = workerClass.newInstance();
      worker.start(request, response);
   }
}

public interface Worker {
   public void work(Request request, Response response);
}

В своем main методе просто вызовите SlaveManager::configureJob(MyWorker.class) прежде чем вы SlaveManager::handle().

Теперь, я сохранил вещи простыми выше, используя Object.newInstance() для создания Worker, но это не рекомендуемая общая практика. WorkerFactory этого было принято использовать WorkerFactory, но я не хотел вводить новый класс и новый шаблон дизайна, если вы не знакомы с Factory Pattern.

  • 0
    В вашем дизайне Worker больше не является Thread , вы не можете вызвать start() . Кроме того, я не уверен, что OP хочет, чтобы клиент мог изменить поведение work() в любое время, но это должен сказать @Akshat;)
  • 0
    Я знаком с Factory Pattern. Я тоже думал об этом. Но с тех пор, будет только один тип работника. Так что, думаю, заводской шаблон здесь не стоит.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню