¿Es "demasiados métodos" una razón válida para romper la regla de "composición sobre herencia"?

7

Por lo general, prefiero seguir la regla de "composición sobre herencia", hasta que empiece a entrar en el mundo de la GUI de Java.

En mi experiencia, para agregar requisitos personalizados en los componentes de una GUI, por ejemplo, agregar una función personalizada en un JButton, generalmente se crea una clase que se extiende desde JButton de esta manera:

public class CustomButton extends JButton{
    public void customMethod(){
    }
}

Creo que obviamente está violando la regla de "composición sobre herencia", así que trato de lograr esto mediante la composición en lugar de la herencia, pero el problema ocurre: JButton tiene paredes de métodos, si uso la composición, las paredes del método se requieren en mi clase de CustomButton:

public class CustomButton{
    protected JButton button;
    public void customMethod(){
    }

    public void add(PopupMenu popup){
        button.add(popup);
    }

    public void addActionListener(ActionListener l){
        button.addActionListener(l);
    }

    .
    .
    .
}

que puede requerir una lista horrible de métodos para mapear a JButton.

También hay un problema más: no sé cómo tratar con los métodos incorporados que necesitan JButton como parámetros si mi CustomButton no es la subclase de JButton.

Entonces, mi pregunta es, si la clase original tiene demasiados métodos, ¿es razonable usar herencia en lugar de composición?

    
pregunta ggrr 22.07.2016 - 04:38

5 respuestas

6

Lo que composición sobre herencia realmente tiene que decir aquí es que hubiera sido bueno si se hubiera diseñado JButton con polimorfismo de composición por lo que su método CutomButton podría haberse pasado a él. No fue.

Si el cliente necesita acceso a todo lo que JButton proporciona (dudoso), ahora tiene que crear un montón de métodos de delegación en el plano de la caldera si quiere hacer la composición al revés. Hay refactorizaciones automáticas que pueden hacer un trabajo tonto así para usted, pero todavía es asqueroso para el mantenimiento. ¿Quién quiere ver eso? Bleh.

Así haces herencia. ¿Qué le duele eso? Bueno, el problema yo yo no es divertido. Evita eso al no crear múltiples niveles de herencia. El problema con eso es que ahora piensas "ok, uno no va a doler". Y lo mismo ocurre con el siguiente chico. Y el siguiente.

Puedes detener eso con un final en la clase pero eso es un poco F.U. para el siguiente jugador. Puedes hacer por el siguiente jugador lo que deseas que el JButton guy haya hecho por ti. Deje que le pasen algo que implemente un CustomInterface con un customMethod() al que llamará. El nombre elegante para esto es patrón de adaptador de objeto .

Ahora estás haciendo herencia y composición, pero al menos la locura puede llegar a su fin.

    
respondido por el candied_orange 22.07.2016 - 06:17
16

Si honestamente, realmente necesitas un componente tan general como JButton , entonces deberías usar la herencia. "Favorecer la composición sobre la herencia" no significa "nunca usar herencia". Sin embargo, la gente hizo esa frase de moda porque el 95% del tiempo cuando los principiantes creen que necesitan herencia, no la necesitan.

El 95% del tiempo, en realidad no necesita un componente tan general como JButton . Necesitas algo mucho más específico. Por ejemplo, aquí está la interfaz pública completa para un botón personalizado en una aplicación de calculadora que escribí en Java hace un tiempo:

public interface Button
{
    public void setOperation(Operation operation);
    public Operation getOperation();
    public void setEnabled(boolean enabled);
}

Toda la configuración de los objetos compuestos se realizó en los constructores, incluidos los controladores de eventos que llaman a la función principal de la operación establecida actualmente cuando se hace clic. Mirando esta interfaz, no tendrías idea de que fue implementado por una interfaz gráfica de usuario de Swing, lo cual es bueno, porque quiero reutilizar la mayor parte de mi código principal para hacer una versión de Android. Mi interfaz es semántica. Se acopla a las necesidades de mi aplicación, no a las necesidades de una biblioteca GUI aleatoria.

Aprenda a escribir componentes GUI personalizados con interfaces que se parecen más a las mías que a sus versiones de copia casi exactas, y también comenzará a ver los beneficios de la composición sobre la herencia.

    
respondido por el Karl Bielefeldt 22.07.2016 - 06:35
2

La premisa de la pregunta parece ser errónea: al usar la composición, creas algo que tiene un botón, pero no es un botón en sí mismo. La composición no es un reemplazo directo de la herencia.

JButton es una vista. Su clase es otra vista que tiene el botón como parte de él o es un controlador, observando el botón. De cualquier manera: no es un botón. Y nadie esperaría poder invocar métodos de botón en él.

Delegar métodos a una propiedad solo es necesario si tienes que cumplir un contrato, como en el patrón de decoración, por ejemplo. Si necesita acceder al botón, expóngalo a través de un método de obtención, no a través de una delegación de método parcial.

    
respondido por el null 23.07.2016 - 14:15
0

Podría implementar los métodos de delegado que usará con mayor frecuencia, para todos los demás, solo asegúrese de que haya un modo para que un cliente obtenga JButton :

public class CustomButton {
    protected JButton button;

    public void customMethod() {
    }

    public void add(PopupMenu popup) {
        button.add(popup);
    }

    public void addActionListener(ActionListener l) {
        button.addActionListener(l);
    }

    public JButton getButton() {
        return button;
    }
}

Luego, por ejemplo, para deshabilitar el botón:

customButton.getButton().setEnabled(false);
    
respondido por el Dragan Bozanovic 22.07.2016 - 13:56
0

En su caso, no está anulando ninguno de los métodos JButton que está tratando de establecer algunas propiedades en JButton usando su método personalizado, por lo que no es necesario usar la herencia. Puedes usar Patter Design Patter.
Por ejemplo

public class CustomButtonBuilder {

      private JButton button;

      public CustomButtonBuilder(JButton button) {
             this.button = button;
      }

      // the build method is your same customMethod()
      public void build() {
      // here goes the custom setting for your button.
      }
}

En el ejemplo anterior, JButton se crea y el oyente requerido, etc. se configuran usando métodos de establecimiento. Luego se pasa al CustomButtonBuilder donde se agregará su funcionalidad personalizada al objeto JButton .

De esta manera, puede elegir Composición sobre herencia sin escribir tantos métodos.

    
respondido por el Sudheer 22.07.2016 - 15:09

Lea otras preguntas en las etiquetas