0

I had a disscusion with a collegue about approaches to these topics in our project. Im making a Progress System, in short a ProgressMonitor class and a Task class, ProgressMonitor handles an array of tasks. All pretty straight forward stuff. But when it came to the tasks ui, we had to opinions. Each task has his own UI. We agree we should have an HUD class for handling UI. The difference in opinion is, he wants the HUD to handle each specific task's UI and so the HUD class would grow quite big and the task would have near to no logic about its UI. My opinion, The HUD would only handle the logic that is the same for all things in our project that need UI's, and all specific logic is handle by the objects that need UI. Advantage of his is some ownership (objects that need to acces some ui info can easily get it from HUD) My advantages, HUD stay light clean and reusable.

What would be more correct acording to OOP?

Rottjung
  • 493
  • 1
  • 5
  • 15
  • When GUI and Task process are in application, implementing http://wiki.c2.com/?ThreadedCommandObject is usually better choice. GUI can monitor completion status of TaskList, where as Thread that actually performs task is seperately working on each of tasks. I am not sure how reusability came in picture but ownership and responsibility are as described in pattern. – Mahesh Attarde Apr 27 '19 at 06:34
  • Thanks interesting read. Although i think i maybe left out some essential info: we're making a game in unreal. – Rottjung Apr 27 '19 at 10:04

1 Answers1

2

I'll start with questions that will affect the implementation:

  • Question 1: Is the Task closely related to it's UI?

  • Question 2: Is the UI for all tasks the same or has minor differences?

  • Question 3: Do you need to show different UI for each task based on the specific task?

If the answer to Question 1 is Yes and separating the two responsibilies is hard, adding the UI logic to the Task can simply things a lot.

If the answer to Question 2 is Yes then using the classic model/view separation will make writing new tasks easier as you only need to add the task logic to the Task class.

You can have a TasksHUD class who's responsibility will be to handle a list of TaskUI class. Eeach TaskUI class will have a Task associated with it and handle the rendering of UI and presentation logic for this specific task.

This way your TasksHUD class will manage how the list is shown to the user, while each list entry will be handled by the TaskUI class. The task presentation code will be reused.

Task will only have the responsibilities of executing, changing it's status and other things that a task must do in your app (if you give a more details I can a more detaildd and probably more accurate description), while the responsibility of presenting a task will be given to a TaskUI.

This way if you need to change the logic how a task is rendered, you have to change only the TaskUI class.

You can write as many tasks as you wan't without having the need to write a UI related code for those tasks.

If you need to change the Task class you may or may not have to change TaskUI class as the dependecy goes from TaskUI to Task. Some changes will affect the UI some won't.

If the answer to Question 3 is Yes then:

You can add the responsibility of handling it's UI to the Task. This way it would be easier to change them as they are in the same class. One problem here is that the Task class can grow having multiple responsibilies. Also sharing rendering code for similar tasks etc.

Event in this case you can decouple the Task from it's UI in two classes Task and TaskUI but you will need a mechanism in your app that will associate a specific Task class with it's TaskUI class. This can lead to more classes and a complexity that may not wan't to manage. In the long run it may save you time (mostly from chaising bugs).

Here is a pseudo code example:

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);
    }
  }

When a task is added your TasksHUD can use the TaskUIFactoryRegistry to get a TaskUIFactory that will create a TaskUI.

Here are some resources that you can check that discuss these kind of issues:

expandable
  • 2,180
  • 7
  • 15
  • The workings of the UI are mostly the same: show title and description on activation, if needed accept decline buttons, show progress once started, show end message when finished. Visually the show progress can be totally different, so each task will have its own userwidget which also handles some of the unique logic for the UI. Since the tasks can have some different settings like a delayed start, objectives in a task being a sequence... it affects the ui, its mostly this i dont want in the HUD but let the task handle. – Rottjung Apr 28 '19 at 00:42
  • Can you add all of these properties to the Task interface (isStartDelayed, isInSequence, Objectives) and let the TaskUI change it's appearance based on the values of these properties? If you can then you can still decouple them and reuse a single TaskUI for all Tasks. It will look different based on the Task state and no UI code will be in the Task itself – expandable Apr 28 '19 at 09:27
  • I agree with your design, but in our case i think it's overkill to add the UITask. We could put most UI logic in the widget blueprint, as a replacment of the UITask. None the less i'll mark your post as the answer. Thanks for your time. – Rottjung Apr 29 '19 at 01:29