¿Cómo hago para que este ejemplo de apertura / cierre obedezca también a la responsabilidad única?

7

Este es un ejemplo simple, pero refleja una tensión entre los principios SÓLIDOS con los que a menudo me encuentro luchando.

Un ejemplo popular del principio abierto / cerrado (por ejemplo, [1] , [2] ) imagina que tiene muchas clases de Forma y un método drawShape() , por ejemplo :

// Open-Close Principle - Bad example
 class GraphicEditor {

    public void drawShape(Shape s) {
        if (s.m_type==1)
            drawRectangle(s);
        else if (s.m_type==2)
            drawCircle(s);
    }
    public void drawCircle(Circle r) {....}
    public void drawRectangle(Rectangle r) {....}
 }

Al utilizar el principio abierto / cerrado (OCP), observamos que este código debería modificarse para cada nueva forma que agregamos; queremos cerrar la necesidad de modificación y permitir la extensión como una mejor manera de agregar un nuevo comportamiento.

Los ejemplos ofrecen lo siguiente como una solución compatible con OCP:

// Open-Close Principle - Good example
 class GraphicEditor {
    public void drawShape(Shape s) {
        s.draw();
    }
 }

 class Shape {
    abstract void draw();
 }

 class Rectangle extends Shape  {
    public void draw() {
        // draw the rectangle
    }
 } 

Como una demostración de OCP en el resumen, este es un buen ejemplo. Sin embargo, esta solución me parece una violación flagrante del principio de responsabilidad única (SRP) . Comenzamos con la "responsabilidad de dibujar", dividida en su propia clase, y resolvimos nuestro problema de OCP agrupando esa "responsabilidad de dibujar" nuevamente con la simple definición de una forma.

Por ejemplo, si el dibujo implica la interacción con una GUI, este ejemplo combina la definición de una forma simple junto con las operaciones de la GUI. Eso parece mal.

¿Qué sería un buen rediseño aquí que se ajustaría a OCP y a SRP?

    
pregunta Standback 20.03.2017 - 12:57

1 respuesta

14

Dibujar en un lienzo. El dibujo no debe requerir interacción con la interfaz de usuario, simplemente la transferencia de la forma dibujada a la interfaz de usuario para que se muestre.

interface Shape {
    void draw(Canvas canvas);
}

class GraphicEditor {
    private Canvas mainCanvas;

    void drawShape(Shape s, Point location) {
        Canvas subCanvas = mainCanvas.subCanvas(location, s.width, s.height);
        s.draw(subCanvas);
        mainCanvas.copy(subCanvas, location);
    }
}

Una respuesta más general:

Diseñe sus métodos para transferir datos, en lugar de tener efectos secundarios. Defina los DTO (como un lienzo) y transfiéralos a la jerarquía.

Cada objeto tiene colaboradores. Piense en ellos como los servicios que utiliza el objeto principal para obtener información y realizar tareas que no forman parte de su responsabilidad principal (SRP). Los DTO resultantes son el "producto" de esos servicios. El objeto principal puede hacer con estos productos lo que desee (dibujarlos en la pantalla, enviarlos por cable, almacenarlos en una base de datos, ...)

    
respondido por el marstato 20.03.2017 - 13:04

Lea otras preguntas en las etiquetas