Tengo un conjunto de clases, cada una de las cuales necesita decidir en algún momento cuál de dos o tres enfoques deberían usar internamente para implementar la misma funcionalidad externamente. Idealmente, esto debería incluir la funcionalidad de repliegue, donde si ApproachA falla, se produce un intento de acercarse a ApproachB (y quizás acercarse a C, D, etc.). Hasta ahora, he estado usando codificación como if (!success) { ApproachB code }
. El problema con esto es que varios métodos posteriores también deben conocer qué enfoque se eligió y todos ellos desarrollan sus propias declaraciones if (MethodChosen) { } else { }
también. Realmente quiero abordar el problema con algo menos difícil de manejar ... excepto que ninguna de las otras opciones que he considerado parece tan "manejable". Estos son los tres enfoques que pensé:Implementando Clases de "retroceso"
- implementar un método .Create estática que decide cuál de las dos clases derivadas para crear, en donde las dos clases tienen una interfaz que los respalda. La desventaja de esto es que está escribiendo mucho del mismo código dos veces, y en realidad no está creando un "retroceso", ya que obliga a todas las decisiones a realizarse por adelantado en el método .Create. Esto debería funcionar 9/10 veces, pero habrá otras 1/10 veces en las que quiero que la reserva entre solo cuando la primaria haya intentado y haya fallado.
- Lo mismo que arriba, pero con una clase base o abstracta involucrada, ya sea como una clase de respaldo para ambos, o con el primario como la clase base para el respaldo. Esto tiene la misma desventaja de respaldo, pero al menos hay poco o ningún código repetido.
implementar una clase abstracta construida normalmente con clases de niño que se puede cambiar en tiempo de ejecución: es decir
public void SomeMethodOrConstructor() { if (someConditions) MyChild = ChildClassA; else MyChild = ChildClassB; } public void Execute() { MyChild.Execute(); }
El problema con la opción 3 está pasando datos entre los dos cuando sea necesario. Dado que algunos de estos métodos están modelando objetos externos, eso será bastante frecuente. ¿Las clases anidadas comparten datos con su clase principal automáticamente? ¿O tendré que pasarlo todo con cada llamada?
¿Algo más que debería considerar?
Actualización: La primera clase está funcionando con la Cadena de responsabilidad. Por el momento, he optado por no utilizar el Patrón de Estrategia o el respaldo durante la ejecución del método, ya que creo que puede ser innecesario al final. Creo que la mayoría de estas ejecuciones fallidas mejorarán al permanecer dentro de sus propias clases, ya que no habrá un cambio completo en el plan de juego, solo algunos retoques menores con los que lidiar. Si ese no es el caso, al menos sabré qué es lo que necesito investigar ahora.
¡Gracias a todos los que ayudaron con la solución definitiva!
Para los curiosos, mi última solución funcionó más o menos así:
- Crear clase abstracta Handler, más o menos como se describe en el artículo de Wikipedia, pero con una función
public abstract Handler GetHandler()
, y la adición de otros métodos abstractos como carga, Guardar, etc. - Implementar subclases de manejador privado para la clase principal (también podrían ser subclases, ya que solo manejarán cosas para esa clase en particular ... también evita problemas de nombres posteriores). Todas las clases secundarias toman un parámetro del tipo del objeto principal en su constructor, por lo que tienen fácil acceso a los datos del padre.
- Desde el constructor de la clase padre, configure los controladores/sucesores de Cadena de responsabilidad (de nuevo, como en el ejemplo), luego llame al
FirstHandler.GetHandler(this)
y almacene el resultado para que la clase sepa qué controlador usar en el futuro. - La mayoría de los métodos manejados simplemente reducen a
Handler.MethodName()
.
Puede poner el código en una lista numerada al sangrarlo con _eight_ espacios. – SLaks
Gracias por el consejo de formateo, ¡eso me estaba llevando por la pared! – RobinHood70