Aquí está mi problema: quiero leer la entrada de diferentes dispositivos HID, como un gamepad, carreras, joystick, etc. Casi cualquier controlador de juegos. El problema es que todos tienen diferentes entradas.
El gamepad tiene botones, interruptores y palos, mientras que el pozo de carreras podría tener una palanca de cambios. Logré abstraer todos estos componentes diferentes en solo 3, así que en lugar de tener una clase base con todas las combinaciones posibles:
abstract class Device
{
public Buttons Buttons;
public Axes Axes;
public Switches Switches;
public GearSticks GearSticks;
//many more
}
Ahora puedo tener:
abstract class Device
{
public Buttons Buttons; //on or off
public Axes Axes; //range [-100%:100%]
public Switches Switches; //multiple states
}
Al principio estaba contento con esto, ya que parecía cubrir todos los tipos posibles de entrada y, por lo tanto, mi clase puede permanecer cerrada mientras está abierta a la extensión a través de todas las implementaciones concretas, ya que todo se puede abstraer a solo 3 tipos de entrada.
PERO entonces pensé para mí mismo ¿qué pasa si solo estoy retrasando lo inevitable? ¿Qué pasa si algún día tendré que agregar otro campo a mi Device
clase? ¡No es compatible con algo como un trackball!
¿Hay alguna manera de que pueda probar esta clase en el futuro? A mi modo de ver, terminaría con algo como esto:
public Device1 : Device
{
//buttons
//trackball
}
public Device2 : Device
{
//Switch
//Axis
}
public Device3 : Device
{
//trackball
//switch
}
Y tendría que seguir agregando propiedades a mi clase base cada vez que haya algo nuevo que implementar.
fuente
parameter1=value1¶meter2=value2
etc.Respuestas:
Estoy bastante seguro de que esto se puede hacer introduciendo un concepto como un resumen
InputChannel
y dispositivos que tengan una lista configurable de canales de entrada. Un canal de entrada tendrá un nombre, un tipo, tal vez algunos metadatos, y debe ser capaz de producir algún "estado" que se ajuste a ese tipo. Puede haber canales predefinidos como un botón, un hacha o un interruptor, o algún canal nuevo que no conozca actualmente (pero podría agregarse más adelante al introducir una nuevaInputChannel
clase secundaria).De esta manera, un dispositivo se convertirá en una especie de metamodelo, y también necesitará una forma de administrar los estados del dispositivo, que deben corresponder a la lista de canales de entrada del dispositivo.
Sin embargo, ese tipo de enfoque genérico tiene un cierto riesgo de ingeniería excesiva, también conocido como efecto de plataforma interna . Por ejemplo, puede que no sea fácil agregar una funcionalidad específica a un dispositivo genérico, o eventos específicos, o interacciones entre diferentes canales de entrada. También puede ser más difícil de usar y comprender para un usuario de su biblioteca genérica de dispositivos.
Tenga en cuenta que no siempre es beneficioso crear la solución más abstracta posible. Los requisitos cambiantes en el hardware generalmente requieren mucho más esfuerzo para implementarse en el hardware en sí que en el software correspondiente, por lo que a menudo es mejor apegarse a una solución más específica en el software y cambiar el software cuando sea necesario.
fuente
InputChannel
puede funcionar, todo lo que necesito hacer es actualizar su estado y aumentar unonChangedEvent
. Pero puede que tengas razón sobre el exceso de ingeniería ... Voy a tener esto en cuenta. ¿Crees que es aceptable agregar otro campo a una clase de vez en cuando?La idea detrás del principio abierto-cerrado es que es menos probable que rompa la funcionalidad existente si implementa una nueva funcionalidad a través de la herencia en lugar de la modificación de una clase existente. Y puedes hacerlo, heredando de tu Hid. En un año y un par de meses, puede crear un Hid2020 que hereda de Hid y agrega soporte para el trackball que se inventará en el cuarto trimestre de 2019. Después de la invención y popularización del detector de compresión en 2023, puede crear una clase Hid2024 que desciende de Hid2019.
Ese sería el enfoque defensivo. Pero también sería un poco descuidado desde una perspectiva de diseño limpio. En su caso, no perdería el sueño por violar O y simplemente cambiaría la clase base a medida que cambia el mundo a su alrededor. No parece que la implementación de trackball o cualquier otro tipo de control nuevo afecte la forma en que maneja presionar botones o cambiar cambios de estado ahora.
fuente