¿Las clases de referencia mutua son una consecuencia del mal diseño? [cerrado]

7

Actualmente estoy trabajando en un juego pequeño que hice en aproximadamente diez días. Ya que estoy programando para mí mismo, estoy siendo perezoso y voy a la solución más fácil con (demasiado) poca preocupación por la mala calidad del código.

Sin embargo, estoy llegando a un punto donde comienza a importar. Estoy empezando a mover valores booleanos que hacen referencia a estados en clases, etc., y ahora quería saber la opinión de programadores experimentados acerca de los objetos de referenciación mutua.

Lo que quiero decir con objetos de referencia mutua es esto: tenemos un servidor que puede crear múltiples juegos, como los juegos de ajedrez cuando dos clientes se conectan para jugar. Cada vez que un jugador hace un movimiento, su controlador de conexión debe actualizar un tablero específico en el servidor. Después de la actualización, una vez que se actualiza la placa, se debe realizar una transmisión del nuevo estado a cada cliente.

Me pareció conveniente tener dos objetos de Cliente en la Junta (de modo que la Junta pueda a Client.send () y una Junta en cada Cliente (de modo que el Cliente pueda llamar a Board.update (mover)). Por alguna razón, me inclino a pensar que esto es generalmente malo y podría evitarse, pero ¿cuál es su opinión?

¿Está bien como está o me falta algo aquí?

    
pregunta Arthur Havlicek 27.09.2015 - 23:23

3 respuestas

8

Tener clases que dependen directamente unas de otras se conoce como acoplamiento. Se toma generalmente como un artículo de fe, sin explicación porque aparentemente ninguna debería ser necesaria, ese acoplamiento es algo malo porque hace que su sistema sea "inflexible".

El problema es que lo único peor que la poca flexibilidad es demasiada flexibilidad. Cuando haces que todo sea lo más flexible posible, terminas con horribles problemas como Soft Coding . Y esa inflexibilidad en realidad puede ser un gran beneficio al darle la vuelta a la desventaja percibida. La desventaja que se cita con frecuencia es que si cambia una cosa, romperá todo a lo que está acoplado y usted también tendrá que cambiar eso. Pero considere esto: los cambios en un subsistema con frecuencia (¡no siempre, pero más a menudo de lo que le gustaría!) Terminan afectando a los subsistemas relacionados de todos modos. Si están fuertemente acoplados, y su idioma tiene un sistema de tipo fuerte y estático, cuando haga un cambio importante, el compilador hará todo el trabajo por usted y le mostrará exactamente lo que tiene que hacer. ser arreglado y donde. Cuanto más se desacoplan las cosas, más difícil es localizar problemas como éste.

Lo que no quiere decir que todo deba estar fuertemente acoplado, por supuesto, especialmente si desea que su código pueda trabajar con diferentes tipos de sistemas relacionados. La gente llama demasiado a una pesadilla de mantenimiento por una buena razón. Pero tenga cuidado de simplemente desacoplar todo para disociar todo, porque eso puede ser aún peor.

En este caso particular, parece que no está intentando que su código funcione con múltiples tipos de sistemas diferentes. Su cliente no está tratando de poder ejecutar "un tablero de ajedrez, un tablero de damas, un tablero de backgammon o un tablero de Scrabble"; es simplemente jugar al ajedrez. Por lo tanto, tener conocimiento de la clase de la Junta no es un problema. Del mismo modo, la Junta no está tratando de comunicarse con varios clientes diferentes, por lo que no necesita ser flexible en el tipo de cliente con el que trata de comunicarse y, por lo tanto, no necesita la complejidad adicional que conlleva hacer es flexible Este es un principio de programación pragmático muy importante conocido como YAGNI (¡No lo va a necesitar!) Tenga esto en cuenta, y deberías hacerlo bien.

    
respondido por el Mason Wheeler 28.09.2015 - 17:14
6

Sí, esto puede ser un problema.

Cuando A depende de B, eso significa que los cambios en B a menudo requieren cambios en A también. Cuando A y B dependen entre sí, eso significa que los cambios en uno de los dos a menudo requieren cambios en el otro. Para fines de mantenimiento, una vez que dos clases se hacen referencia mutuamente, también podrían ser una gran clase.

Al igual que muchos problemas de arquitectura de software, solo una referencia mutua como el ejemplo que usted describe es poco probable que sea un problema importante por sí solo, pero si nunca elimina esta referencia mutua cuando se convierta en una molestia, hará muchos cambios futuros innecesariamente. fiddly Y si te permites agregar más referencias mutuas, te arriesgas a convertir todas tus clases pequeñas en una clase divina de facto que ya no puedes desenredar.

Como ejemplo muy simple de lo que estoy hablando, imagine que desea agregar un modo de espectador o una tabla de clasificación en línea o alguna otra característica que requiera enviar el estado de la placa a "clientes" que no sean los otros jugador. El cliente tiene que cambiar sin importar qué, ya que necesita saber cómo llamar a SpectatorBoard.update () y Leaderboard.addScore () así como a Board.update (), pero debido a la referencia mutua, Board también tiene que cambiar para que puede llamar a Spectator.send () y Leaderboard.sendScore (). Ahora su compleja lógica de red está dispersa en dos clases, una de las cuales claramente no tiene nada que ver con esto con mucho detalle.

Sin saber más sobre sus requisitos, el código actual y el lenguaje de programación, es imposible decir cuál es la alternativa correcta, pero voy a suponer que la necesidad de enviar actualizaciones "se originó" en la Junta de alguna manera (tal vez sea la única manejando la entrada del usuario), en cuyo caso, una alternativa obvia es enseñar a la Junta a activar un evento (suponiendo que su idioma admita eventos, también conocido como patrón Observer), y luego simplemente haga que el Cliente se suscriba a ese evento. Entonces, el Cliente puede seguir siendo la única clase que necesita conocer su lógica de red.

    
respondido por el Ixrec 28.09.2015 - 02:10
0

El enfoque del hombre pobre aquí es crear un patrón de diseño de Mediador, donde las dos clases mencionadas solo se comunican con el mediador y el mediador conoce las dos clases. Puede llevarlo tan poco como desee con interfaces en lugar de clases concretas, fábricas para construir los componentes, etc., ¡pero un mediador definitivamente hará que cualquier posible refactor sea más sencillo en el camino!

    
respondido por el Ovan Crone 28.09.2015 - 17:26

Lea otras preguntas en las etiquetas