Claro, pero llamamos a eso composición y delegación . El patrón de estrategia y la inyección de dependencia pueden parecer estructuralmente similares, pero sus intenciones son diferentes.
El patrón de estrategia permite la modificación del comportamiento en tiempo de ejecución bajo la misma interfaz. Podría decirle a un pato silvestre que vuele y verlo volar con alas. Luego cámbielo por un pato piloto y véalo volar con Delta Airlines. Hacer eso mientras el programa se está ejecutando es una cuestión de Patrón de estrategia.
La inyección de dependencias es una técnica para evitar dependencias de codificación dura para que puedan cambiar de forma independiente sin requerir que los clientes sean modificados cuando cambian. Los clientes simplemente expresan sus necesidades sin saber cómo se satisfarán. Por lo tanto, cómo se cumplen se decide en otro lugar (generalmente en main). No necesitas dos patos para hacer uso de esta técnica. Simplemente algo que usa un pato sin saber o importar qué pato. Algo que no construye el pato o lo busca, pero está feliz de usar cualquier pato que le des.
Si tengo una clase de pato concreta, puedo hacer que implemente su comportamiento de vuelo. Incluso podría hacer que cambie los comportamientos de volar con alas a volar con Delta en función de una variable de estado. Esa variable podría ser un booleano, un int, o podría tener FlyBehavior
un fly
método que haga cualquier estilo de vuelo sin que tenga que probarlo con un if. Ahora puedo cambiar los estilos de vuelo sin cambiar los tipos de pato. Ahora los ánades reales pueden convertirse en pilotos. Esto es composición y delegación . El pato está compuesto por un FlyBehavior y puede delegarle solicitudes de vuelo. Puede reemplazar todos sus comportamientos de pato de una vez de esta manera o mantener algo para cada comportamiento o cualquier combinación intermedia.
Esto le da a todos los mismos poderes que tiene la herencia, excepto uno. La herencia le permite expresar qué métodos de Duck está anulando en los subtipos de Duck. La composición y la delegación requieren que Duck delegue explícitamente los subtipos desde el principio. Esto es mucho más flexible, pero implica más tipeo del teclado y Duck tiene que saber que está sucediendo.
Sin embargo, muchas personas creen que la herencia debe diseñarse explícitamente desde el principio. Y que si no lo ha sido, debe marcar sus clases como selladas / finales para no permitir la herencia. Si toma esa opinión, la herencia realmente no tiene ventaja sobre la composición y la delegación. Porque entonces, de cualquier manera, debe diseñar la extensibilidad desde el principio o estar dispuesto a derribar las cosas más adelante.
Derribar cosas es en realidad una opción popular. Solo tenga en cuenta que hay casos en los que es un problema. Si ha implementado de forma independiente bibliotecas o módulos de código que no tiene la intención de actualizar con la próxima versión, puede terminar atrapado con versiones de clases que no saben nada sobre lo que está haciendo ahora.
Si bien estar dispuesto a derribar las cosas más tarde puede liberarlo de un diseño excesivo, hay algo muy poderoso en poder diseñar algo que use un pato sin tener que saber qué hará realmente el pato cuando se use. Que no saber es algo poderoso. Te permite dejar de pensar en patos por un tiempo y pensar en el resto de tu código.
"Podemos" y "deberíamos" son preguntas diferentes. Favorecer la composición sobre la herencia no dice nunca usar la herencia. Todavía hay casos en los que la herencia tiene más sentido. Te mostraré mi ejemplo favorito :
public class LoginFailure : System.ApplicationException {}
La herencia le permite crear excepciones con nombres descriptivos más específicos en una sola línea.
Intenta hacerlo con la composición y obtendrás un desastre. Además, no hay riesgo del problema de herencia yo-yo porque no hay datos o métodos aquí para reutilizar y fomentar el encadenamiento de herencia. Todo esto agrega es un buen nombre. Nunca subestimes el valor de un buen nombre.
Duckbehavior.quackBehavior
y otros campos en su código?