Tengo una clase (vamos a llamarlo verificador) y diferentes tipos de clases que ejecutan tareas (vamos a llamarlas tareas). cada tarea pertenece a varias categorías

Cada tarea se ejecuta y en algún momento pregunta al verificador si se les permite hacer algo. el corrector responde según el estado del sistema y según su categoría. una tarea puede estar en múltiples categorías

¿Cómo implementaría eso? (cpp pero realmente no creo que sea específico del lenguaje).

Estaba pensando en agregar una lista de categorías en cada tarea y tener una función que obtiene una categoría y responde si la tarea le pertenece.

class checker {
    bool is_allowed(Task * task);
}

class Task
{
    bool is_belongging_to_category(Category cat);
    void some_task_to_do()
    {
        ...
        if (checker::is_allowed(this)) { ....}
        else {....}
    }
}

¿Hay una mejor manera de resolver esto? Tal vez algún patrón de diseño conocido ...

1
Epic 4 ene. 2017 a las 18:32

4 respuestas

La mejor respuesta

Esto parece un diseño cuestionable. Estás haciendo tareas de los objetos.

Digamos que sus tareas son: Comer , Beber y Be_Merry

Si hace que cada una de esas tareas sean objetos, tendrán que mantener una referencia al individuo real en el que operan, luego, cuando se cumpla la condición, deberán modificar el estado del individuo dado.

Esto es una violación de Diseño orientado a objetos que define un objeto como:

Un fuerte acoplamiento o asociación de estructuras de datos con los métodos o funciones que actúan sobre los datos.

Observe que ha separado los "métodos o funciones que actúan sobre los datos" del objeto. En su lugar, debería haber modelado los objetos Jack y Jill que tenían métodos : Comer , Beber y BeMerry

En cuanto a checker, si está dividido dependerá de si está utilizando un push o una codificación de extracción. Si está haciendo una codificación de inserción, entonces el verificador es simplemente un área de retención para las propiedades de comportamiento de Jack y Jill , en tal caso, las propiedades se deben insertar en Jack y Jill en lugar de mantenerse en checker. Si son propiedades para todos los objetos Jack o Jill , use una propiedad static. Sin embargo, si está utilizando la codificación de extracción, la información no estará disponible hasta que intente ejecutar la tarea. En este caso, checker probablemente debería ser un singleton al que Jack y Jill acceden en el proceso de realizar sus tareas.

EDITAR:

Su comentario revela más tragedia en el diseño. Parece que has lanzado un montón de hilos que están ocupados esperando en checker. Esto indica que necesita usar una codificación pull. Sus objetos Jack y Jill necesitan mantener booleanos para las tareas en las que participan activamente, por ejemplo m_is_going_to_school, y luego cuando checker la condición que detendría su espera ocupada en su diseño, en lugar de eso, inicie el método goToSchool.

0
Community 23 may. 2017 a las 11:45

Podría hacer un vector para almacenar todas las opciones permitidas posibles. Puede hacer una función bool (como la que tiene) llamada IsAllowed con cadena de argumento y eso verificará si la opción que va a hacer está permitida. Si no, devuelve falso. Sin embargo, esa es solo mi idea. Por supuesto, hay muchísimas formas diferentes de implementar esto. Si quieres múltiples opciones. Luego puede hacer un vector 2D y ver si la fila correspondiente tiene alguna de las opciones. ¡Buena suerte!

0
Verideth 4 ene. 2017 a las 15:38

Si conoce el número máximo de categorías de antemano, le recomiendo usar Bit Flags para hacer esto.

enum Category {
    CATEGORY_A = 1,
    CATEGORY_B = 1 << 1,
    CATEGORY_C = 1 << 2,
    CATEGORY_D = 1 << 3,
};

class Task {
  int32_t categories_;
public:
  Task() : categories_(0) {}

  void add_category(Category cat) {
    categories_ |= cat;
  }

  void run() {
    checker::can_run(categories_);
  }
} 

Esto permite probar varias categorías a la vez:

namespace checker {

bool can_run(int32_t categories) {
  int32_t cannot_run_right_now = CATEGORY_A | CATEGORY_C;   

  if(categories & cannot_run_right_now != 0) {
     return false;
  }
  ...
}
}
0
Frank 4 ene. 2017 a las 15:52

Bueno, eso depende. Si está 100% seguro de saber cuántas categorías hay y que no es un número gigantesco, entonces puede almacenar esta información como un número entero. Si el n-ésimo bit es 1, entonces la tarea pertenece a la n-ésima categoría. Luego, depende del estado del sistema en el que pueda crear otro entero que sirva como máscara. Al final, solo haría una operación de bit-AND (máscara y categorías! = 0) para determinar si la tarea y la máscara comparten un bit común.

Por otro lado, si habrá un número desconocido de categorías, puede hacer una lista de categorías a las que pertenece. Haga un diccionario de [SYSTEM_STATE] => [CATEGORIES_AVAILABLE] y verifique

  bool is_allowed(Task * task){
    foreach (Category sysC in stateCategories[sys.GetState()])
    {
       foreach (Category taskC in task.GetCategories()) 
       {
         if(sysC == taskC) return true;
       }
    }
    return false;
    }

Eso, por supuesto, sería lento para una gran cantidad de categorías. Puede mejorar este método haciendo que esta lista de categorías sea otra estructura de datos, en la que la búsqueda no es O (n) de modo que el código se vea así:

  bool is_allowed(Task * task){
    foreach (Category sysC in stateCategories[sys.GetState()])
    {
       if task.GetCategories().Contains(sysC) {
         return true;
       }
    }

Depende

0
Maciej Długoszek 4 ene. 2017 a las 15:53