¿Es "incorrecto" / mal diseño poner un subproceso / trabajador de fondo en una clase?

15

Tengo una clase que leerá de Excel (C # y .Net 4) y en esa clase tengo un trabajador en segundo plano que cargará los datos de Excel mientras la interfaz de usuario puede seguir respondiendo. Mi pregunta es la siguiente: ¿Es un mal diseño tener un trabajador de fondo en una clase? ¿Debo crear mi clase sin ella y usar un trabajador en segundo plano para operar en esa clase? Realmente no puedo ver ningún problema de crear mi clase de esta manera, pero de nuevo soy un novato, así que pensé que me aseguraría antes de continuar.

Espero que esta pregunta sea relevante aquí, ya que no creo que deba estar en stackoverflow ya que mi código funciona, esto es solo un problema de diseño.

Jetti
fuente
3
¿Por qué crees que podría estar mal?
Alb
1
@Alb: es difícil de decir. Mi código funciona y satisface mis necesidades, sin embargo, estoy planeando usar esto en un proyecto que haré de código abierto. Quiero asegurarme de que mi código "no solo funcione" y que esté bien diseñado.
Jetti

Respuestas:

21

¿Debo crear mi clase sin ella y usar un trabajador en segundo plano para operar en esa clase?

Si deberías. Y le diré por qué: está violando el Principio de responsabilidad única . Al acoplar firmemente la clase que accede al documento de Excel con la forma en que accede al documento de Excel, elimina la posibilidad de que el código del "controlador" (cualquier código que use esto) lo haga de una manera diferente. ¿Qué tan diferente, puedes preguntar? ¿Qué sucede si el código del controlador tiene dos operaciones que toman mucho tiempo pero quieren que sean secuenciales? Si le permitiste al controlador la capacidad de manejar el subproceso, puede realizar ambas tareas de ejecución prolongada juntas en un subproceso. ¿Qué sucede si desea acceder al documento de Excel desde un contexto que no es de interfaz de usuario y no necesita que se enhebre?

Al trasladar la responsabilidad de enhebrar a la persona que llama, permite una mayor flexibilidad de su código, haciéndolo más reutilizable.

Nemi
fuente
2
+1 por responder la pregunta real que se hizo y responderla bien.
Adam Lear
+1 - Gracias Nemi. Respondiste a mi pregunta, te lo agradezco. Sacaré eso de mi clase y lo pondré en una nueva clase, ¡gracias de nuevo!
Jetti
@Nemi: ¿sería aceptable si creara otro método que tuviera una carga síncrona y luego tuviera un método asíncrono? ¿O sería mejor tener el único método de carga sincrónica y luego ir desde allí?
Jetti
1
Yo personalmente no tendría un método de sincronización y un método asíncrono. Sigues acoplando responsabilidades. He trabajado con este problema exacto muchas veces. Lo que hice fue crear un TaskController que fue modelado a partir de SwingWorker, pero tenía un código específico para nuestra aplicación. El TaskController hizo cosas como actualizar una barra de progreso, cambiar el cursor del mouse, etc. Puede parecer que el código de placa de caldera siempre tiene que crear un TaskController para hacer llamadas, pero en última instancia el código es más robusto y más fácil de mantener.
Nemi
Gracias Nemi! Ojalá pudiera volver a votarte porque definitivamente respondiste mi pregunta y me indicaste en la dirección correcta. ¡¡Gracias de nuevo!!
Jetti
3

Es un buen diseño que las operaciones de la interfaz de usuario operen en un hilo separado de las tareas en segundo plano. De lo contrario, la interfaz de usuario deja de responder cuando la aplicación está ocupada.

Si puede separar la parte que funciona en el subproceso de fondo a su propia clase, el código será más limpio.

Alba
fuente
1
Aunque correcto, por cómo leí su pregunta, no tiene problemas para entender este punto.
Nemi
Lo siento si mi pregunta fue mal leída. Sé que separar la interfaz de usuario y las tareas en segundo plano es un buen diseño (si no es necesario, mi archivo de Excel de prueba tiene más de 8k filas y haría que el programa no responda). Mi pregunta es, básicamente, ¿es bueno acoplar estrechamente el hilo con la clase de Excel?
Jetti
0

Separaría tu IU de tu tarea en segundo plano usando clases separadas. Hacerlo alienta la separación de las preocupaciones. El código de interfaz de usuario y la lógica empresarial no deben mezclarse.

Ryan Michela
fuente
Para ser claros, mi clase no toca la interfaz de usuario. Tiene dos eventos que permitirían lo que sea que lo esté usando para actualizar la IU si es necesario, pero mi clase en sí misma no toca la IU.
Jetti
0

De lo que recuerdo sobre BackgroundWorkers es que proporcionan una serie de métodos de conveniencia, como la capacidad de enviar actualizaciones de progreso a la interfaz de usuario. Sin embargo, no hay una regla que diga que no puedes usarlo desde una clase diferente.

Además, si está haciendo una iteración que no requiere que los elementos se procesen en un orden específico, considere usar ThreadPool en su lugar (o si está en .NET 4 use la Biblioteca de tareas paralelas ).

Michael Brown
fuente
Gracias por su respuesta. Creé dos eventos en mi clase que activarán el progreso (básicamente envolviendo el evento de progreso BackgroundWorker, ya que BackgroundWorker es privado) que envía el progreso a la UI (barra de progreso).
Jetti