vendredi 12 août 2022

Design pattern for complex hierarchy

I'm trying to implement an application to solve a given task, made up of small sub-tasks. Individual workers are in charge of handling a portion of each sub-task. Then a coordinator regroups all the plans made by each worker and builds a global solution to the full task.

There may only be one worker assigned to each sub-task, but he does not have to complete it in its entirety; he can give a plan for only part of the sub-task, and then let the coordinator complete it as he is building the global solution (typically this gives the coordinator more flexibility as he can make plans from different workers fit better with each other but increases his workload). Furthermore, as they are created, plans are first sent to the coordinator, who can either directly reject it or ask the worker to store it for future use.

At any given time, a worker can send an alert to the coordinator if he thinks there is an issue with the plans he is producing. The coordinator will look at it in the future, and can then ask said worker to delete some of the plans he has already created and change the parameters he uses to crate future plans.

Finally, for a worker in charge of a certain portion of a certain sub-task, multiple methods are available to him. All methods generate the same plans, but one may be more efficient than another in a given context. The chosen method may not change during solving.

For the moment, the classes I have created look something like this:

class Subtask {
    // Concrete classes will contain various data relative to the sub-task
};

class Worker {
    const Subtask& subtask;
    // Concrete classes will have various objects relative to the portion this worker should solve
    Method method;

    vector<Plan> createdPlans;

    virtual Plan createPlan() {method.createPlan;}
    virtual void storePlan(Plan plan) {createdPlans.push_back(plan);}

    virtual Alert createAlert() = 0;
    virtual void applyAlert(Alert alert) {
        // remove plans from createdPlans according to the alert
        method.applyAlert(alert);
    }
}

class Method {
    const Subtask& subtask;

    virtual Plan createPlan() = 0;
    virtual void applyAlert(Alert alert) = 0;
};

class Plan {
    // Concrete classes contain various data relative to the plan
};

class Alert {
    const Worker& worker;

    virtual void trigger() {worker.applyAlert(this)}
};

Worker and Method hold references to their Subtask as they may regularly need data from it. Alert holds a reference to the Worker that created it to know who to apply to if the coordinator decides to trigger it.

For a given portion of a given sub-task, I need to implement specific Worker, Plan and Alert, and various Methods relative to that Worker.

I'm mainly facing two issues:

  1. In concrete implementations of Worker, createdPlans will only contain elements of the associated sub-class of Plan. For instance, in applyAlert, I need to cast them to access their specific data and verify if they should be removed by the alert or not. However, the coordinator also needs to iterate and do generic actions over them, so createdPlans needs to exist in Base class Worker.

  2. In implementations of Worker and Method, in applyAlert, I need to cast the alert to the sub-class corresponding to that type of Worker as I need specific information from it. Visitor pattern would not be adapted here, as only one type of Alert can actually be applied to a concrete Worker/Method.

Aucun commentaire:

Enregistrer un commentaire