Lo que no entendi y me parece interesante saber es porque el OOP es malo para la reusabilidad del codigo (basado en herencia y esas cosas).
Te lo explico con un ejemplo.
Pensemos como implementar la lógica del tetris mediante OOP.
Alguien que piensa la reusabilidad por herencia llegaría a la conclusión que las piezas comparten casi todo salvo la forma, luego si hacemos una clase base que haga todo salvo definir la forma de la pieza, cada pieza tendría únicamente que completar una matriz que indique la forma y listo.
Un poco de pseudocódigo:
class FallingPiece {
fall() { ... }
moveLeft() { ... }
moveRight() { ... }
rotateLeft() { ... }
rotateRight() { ... }
occupies(x, y) { ... }
}
class TPiece : FallingPiece {
TPiece() {
this.shape[0][0] = FallingPiece.FILL;
this.shape[1][0] = FallingPiece.FILL;
this.shape[2][0] = FallingPiece.FILL;
this.shape[1][1] = FallingPiece.FILL;
}
}
A simple vista la clase base parece satisfacer un cierto grado de reusabilidad, ya que podriamos continuar usandola para cualquier tipo de pieza que se nos ocurra.
PERO
¿Qué pasa si ahora viene el game designer con una nueva propuesta de un juego que sigue una mecánica muy parecida a la del tetris pero donde las piezas estas compuestas por elementos de diferentes colores, y el objetivo es formar filas de tres o más elementos del mismo color (puzzle pirates)?
¿Podrías reusar el código anterior sin que este deje de funcionar también para la lógica del tetris original?
Acá es cuando la herencia viene y te dice "ah! gotcha sucker!" mientras realiza movimientos pelvicos oscilatorios (en el hipotético caso que un concepto pudiera hablar y tuviera una forma corpórea).
----
¿Cuál es el error en la implementación anterior?
La clase base está cumpliendo más funciones de las que debería. Al darle la responsabilidad de manejar la forma de las piezas rompimos la generalización de este objeto. En el momento en que cambio ligeramente la composición de esta forma, esta clase base dejo de ser utilizable.
Veamos ahora como hubiera sido lo mismo pensado desde la reusabilidad por interfase. En este caso buscamos cual es la interfaz común para todas las "piezas que caen". Tenemos que poder hacerlas caer un espacio a la vez, rotarlas y moverlas horizontalmente (lo mismo que contemplamos en el ejemplo anterior). No sabemos nada sobre la forma, eso lo sabe el objeto concreto para cada tipo de pieza, pero sabemos que ocupa cierto espacio. Necesitamos saber si la pieza ocupa o no cierta casilla del espacio de juego, pero la responsabilidad de responder a esto se la tenemos que pasar al objeto concreto (porque no conocemos la forma de la pieza). Sin embargo si sabemos un dato, que el objeto concreto necesita saber, el centro de la pieza, o sea, la posición central de la pieza (centro de rotación/traslación).
Luego veamos el pseudocódigo:
class FallingPiece {
protected x, y, angle;
// las acciones estas las puede manejar la clase base ajustando los valores de posición
// y observando los cambios para detectar colisiones
// pero no le hace falta saber a priori la forma
fall() { ... }
moveLeft() { ... }
moveRight() { ... }
rotateLeft() { ... }
rotateRight() { ... }
// esto se lo tenemos que dejar al objeto concreto
virtual occupies(x, y);
}
class TPiece : FallingPiece {
occupies(x, y) { ... }
}
Ahora, viene de nuevo el game-designer con su rip-off del tetris. ¿Qué hacemos?
class FallingColoredPiece : FallingPiece {
virtual getColor(x, y);
}
class TwoColorsPiece : FallingColoredPiece {
occupies(x, y) { ... }
getColor(x, y) { ... }
}
----
Es un ejemplo medio burdo pero no sé me ocurrió nada mejor para explicar el tema.
OOP no es malo para la reusabilidad, solo requiere un cuidado extra en el diseño. Lo que sucede es que muchas veces genera la falsa sensación de reusabilidad, y es difícil extirpar estas malas prácticas (en especial cuando hay profesores que las enseñan como buenas).
----
El paradigma estructurado usado mal tampoco va a ayudar a la reutilización del código.
(Psst... ojo que el paradigma estructurado es el de "quememos al GOTO en la hoguera y usemos estructuras de control", no tiene nada que ver con el paradigma procedural. Tanto paradigma confunde mucho

)