Я начну с вопросов, которые повлияют на реализацию:
Вопрос 1: Является ли задача тесно связанной с ее пользовательским интерфейсом?
Вопрос 2: Является ли пользовательский интерфейс для всех задач одинаковым или имеет незначительные различия?
Вопрос 3: Нужно ли показывать разные интерфейсы для каждой задачи в зависимости от конкретной задачи?
Если ответ на Вопрос 1 равен Да , и разделение двух областей ответственности затруднительно, добавление логики пользовательского интерфейса в Task может многое сделать.
Если ответ на Вопрос 2 равен Да , тогда использование классического разделения модель / представление облегчит написание новых задач, поскольку вам нужно всего лишь добавить логику задачи в Задание класс.
Вы можете иметь класс TasksHUD , который будет отвечать за обработку списка класса TaskUI . Каждый класс TaskUI будет иметь Task , связанный с ним, и обрабатывать рендеринг пользовательского интерфейса и логику представления для этой конкретной задачи.
Таким образом, ваш класс TasksHUD будет управлять отображением списка пользователю, а каждая запись списка будет обрабатываться классом TaskUI . Код представления задачи будет использован повторно.
Задача будет только отвечать за выполнение, изменение своего статуса и другие вещи, которые задача должна делать в вашем приложении (если вы предоставите более подробную информацию, я смогу дать более подробное и, возможно, более точное описание) в то время как ответственность за представление задачи будет передана TaskUI .
Таким образом, если вам нужно изменить логику отображения задачи, вы должны изменить только класс TaskUI .
Вы можете написать столько задач, сколько захотите, без необходимости писать код, связанный с пользовательским интерфейсом, для этих задач.
Если вам нужно изменить класс Task , вам может понадобиться или не потребоваться изменить класс TaskUI , так как зависимость меняется с TaskUI на Task . Некоторые изменения повлияют на пользовательский интерфейс, некоторые - нет.
Если ответ на Вопрос 3 равен Да , тогда:
Вы можете добавить ответственность за обработку его пользовательского интерфейса в Task . Таким образом было бы легче изменить их, поскольку они находятся в одном классе. Одной из проблем здесь является то, что класс Task может расти с несколькими ответвлениями. Также делимся кодом рендеринга для подобных задач и т. Д.
Событие. В этом случае вы можете отделить Task от его пользовательского интерфейса в двух классах Task и TaskUI , но вам потребуется механизм, который будет связать определенный класс Task с его TaskUI class. Это может привести к большему количеству классов и сложности, с которыми, возможно, не справиться. В долгосрочной перспективе это может сэкономить ваше время (в основном, от появления ошибок).
Вот пример псевдокода:
interface TaskObserver {
void onTaskChanged(t);
}
interface TaskUI {
void render();
}
interface TaskUIFactory {
register(TaskUIFactoryRegistry registry);
TaskUI create(Task task);
}
interface Task {
TaskStatus status;
execute();
addEventListener(TaskObserver o);
}
class TaskA : Task {
// implementation.....
}
class TaskA_UI : TaskUI, TaskObserver {
TaskA mTask;
TaskA_UI(TaskA task) {
mTask = task;
mTask.addEventListener(this);
}
render() {
// rendering goes here
}
onTaskChanged(t) {
// raise an event or signal to the TaskHUD that a refresh is needed
}
}
class TaskA_UIFactory : TaskUIFactory {
void register(TaskUIFactoryRegistry registry) {
registry.Register(typeof(TaskA), this);
}
TaskUI createUI(Task task) {
return new TaskA_UI((TaskA)task);
}
}
Когда задача добавлена, ваш TasksHUD может использовать TaskUIFactoryRegistry, чтобы получить TaskUIFactory, которая будет создавать TaskUI.
Вот некоторые ресурсы, которые вы можете проверить, чтобы обсудить подобные вопросы: