Usando el patrón de comando para una secuencia de tareas

7

Tengo una 'secuencia de tareas' para realizar en un archivo zip. Se puede simplificar en estos pasos:

  1. Valide que el archivo sea un archivo ZIP y que sea válido
  2. Descomprimir el archivo
  3. Valide que los contenidos sean los esperados
  4. Convierta el contenido en un producto

Actualmente estoy usando el patrón de Comando y se ve un poco como este

interface Command {
    public function execute($data);
}

class ValidateFile implements Command { 
    public function execute($filePath) { //... }
}

class UnzipFile implements Command { 
    public function execute($filePath) { //... }
}

class ValidateContents implements Command {
    public function execute($unzippedFilePath) { //... }
}

class ProductGenerator implements Command {
    public function execute($unzippedFilePath) { //... }
}

Ahora, cada uno de estos comandos de ejecución devuelve una cadena que a su vez (por el invocador del comando) pasa al siguiente comando de la cadena (definido por la configuración).

Estoy teniendo dos problemas aquí:

  1. Cada comando requiere sus propias dependencias, es decir, unzip necesita acceso a ZipArchive, una clase que se encarga de descomprimir los archivos zip. ¿Cómo inyecto las dependencias de cada comando? Estoy muy contento de evitar esto al crear una instancia de todos los comandos a través de un DIC y conectarlos a un 'Invoker' que acepta objetos instanciados de tipo Command, los ejecuta en secuencia, sin embargo, no se siente bien.

  2. (Más de un problema) ¿Cómo puedo persistir más que una cadena entre los comandos? He visto en lugares a personas que pasan un objeto de 'contexto' de un comando a otro, sin embargo esto se siente un poco sucio, ya que el comando dependería de una interfaz sin tipo (esencialmente envuelven una matriz asociativa). Tiene sentido que tenga que ser desincrustado, como si tuviera que mantener una interfaz entre los comandos, entonces el contexto no puede implementar ningún método específico, ya que eso impediría su abstracción.

Agradecería cualquier consejo sobre cómo abordar estos dos problemas.

Editar: Otro problema que tengo es que cada uno de estos comandos está realmente acoplado al estado de la ruta del archivo que se le pasa, son muy específicos para el caso en cuestión, pero dudo que sea posible trabajar más allá de eso .

    
pregunta Matthew Haworth 05.09.2014 - 11:41

1 respuesta

5

A su primera pregunta: es bastante normal que cada constructor de comandos tenga una firma diferente con diferentes dependencias, por lo que la construcción de los comandos no se puede realizar de forma totalmente genérica. El uso de un DIC puede mitigar esto.

Para escenarios más complejos, también puede usar el patrón de "fábrica abstracta", donde tiene una clase de fábrica por comando, todas derivadas de una interfaz de fábrica abstracta, y cada fábrica encapsula las tareas específicas para crear el comando individual . Estas fábricas se pueden pasar a un "FactoryInvoker" genérico. Pero debes pensar dos veces si realmente vale la pena la sobrecarga adicional en el código.

A tu segunda pregunta: pasar un objeto 'contextual' de un comando a otro está bien. Las soluciones genéricas a veces vienen por el precio de reducir algún tipo de seguridad. Si cree que realmente necesita tanta seguridad, convierta al "contexto" en una clase base abstracta, con diferentes subclases, cada una representando un tipo diferente de contexto. Pero tenga cuidado, esto puede conducir fácilmente a una solución totalmente no diseñada en exceso de ingeniería y no flexible, que puede causar mucho esfuerzo cuando tenga que cambiar el flujo de comandos posteriormente.

    
respondido por el Doc Brown 05.09.2014 - 13:29

Lea otras preguntas en las etiquetas