2010-08-03 20 views
5

Tengo una clase que contiene 10 métodos que realizan casi las mismas cosas aparte de un evento clave. Dos ejemplos son los siguientes:eliminar la duplicación


Public String ATypeOperation(String pin, String amount){ 
    doSomething(); 
    doMoreStuff(); 
    requestBuilder.buildATypeRequest(pin, amount); 
    doAfterStuff(); 
} 
 


Public String BTypeOperation(String name, String sex, String age){ 
    doSomething(); 
    doMoreStuff(); 
    requestBuilder.buildBTypeRequest(name, sex, age); 
    doAfterStuff(); 
} 
 

Como se puede ver a partir de los métodos anteriores, son similares, aparte de llamar a diferentes métodos proporcionados por RequestBuilder. El resto 8 son similares también. Aquí hay muchos códigos duplicados. Siento que hay una mejor manera de implementar esto, pero no sé cómo. Cualquier idea y sugerencia es apreciada.

Gracias, Sarah

+1

¿Su solicitud se ha utilizado realmente en el método? – helpermethod

+0

@Helper Sí, lo es. Puede decir que se usa en doAfterSuff(); – sarahTheButterFly

Respuesta

5

usar algo como RequestBuilder, que acepta todos estos tipos de parámetros:

public RequestBuilder { 
    // setters and getters for all properties 

    public Request build() { 
     doStuff(); 
     Request request = new Request(this); 
     doAfterStuff(); 
     return request; 
    } 
} 

y luego

new RequestBuilder().setAge(age).setName(name).build(); 
+0

Tengo una pregunta aquí. Cuando un cliente que utiliza RequestBuilder(), ¿cómo sabe qué parámetros debe establecer? Tome los dos métodos en mi publicación, por ejemplo, tendría que pedirle al cliente que elija establecer 2 de los 5 parámetros posibles. ¿Cómo podemos estar seguros de que el cliente no establecerá un parámetro incorrecto? – sarahTheButterFly

+0

establece lo que quiera (tiene 'a mano'). Si la combinación no es suficiente, lanza una excepción. – Bozho

+0

Usted pasa los parámetros obligatorios en el constructor RequestBuilder y cualquier parámetro opcional mediante llamadas a métodos adicionales antes de llamar a compilación. Para eso está hecho el constructor: muchos parámetros opcionales (para reducir los constructores telescópicos) @bozo, realmente debería establecer los parámetros obligatorios en el constructor de constructores – atamanroman

2
interface RequestBuilder { 
    void doStuff(params); 
} 

public RequestBuilder getARequestBuilder() { 
    return new RequestBuilder() { 
    void doStuff(params) { 
     // impl.details 
    } 
    } 
}  

public RequestBuilder getBRequestBuilder() { 
    return new RequestBuilder() { 
    void doStuff(params) { 
     // impl.details 
    } 
    } 
}  

public String buildRequest(yourParams, RequestBuilder builder){ 
    doBefore(); 
    builder.doStuff(yourParams); 
    doAfter(); 
} 

creo que esto se llama el patrón Strategy. Se parece mucho al patrón Command, pero debido a que encapsula un algoritmo, parece ser Estrategia :)

Lo que Bozho sugiere es el patrón Builder.

Le recomiendo que navegue por a list of patterns alguna vez, o compre Head First Patterns. Lectura realmente divertida

+0

No estaba seguro si este era un patrón de comando o estrategia. Su desacoplamiento de un algo (estrategia) pero, por otro lado, es claramente una llamada a un método encapsulado (comando). Tal vez alguien pueda decir por qué es qué patrón. Diría su comando aunque el método se llame inmediatamente :) – atamanroman

+0

@fielding Supongo que es la intención lo que más importa. Pero solo uso patrones (a veces sin saber que es un patrón :) y no soy un tipo de chico de patrones teóricos. – extraneon

1

Usted podría pasar el objeto a un método constructor buildRequest genérico. Dado que no solo el algoritmo sino también los argumentos varían, los puse en el constructor. No creo que esa es una buena solución, pero yo quería mostrar un patrón de comandos aquí: D (Extraneon mostró cómo desacoplar params y comandos)

// call somewhere in the code: 
    Builder b = new BTypeBuilder(); 
    b.age = "20"; b.sex = "female"; b.name = "eve"; 
    String res = buildRequest(b); 

    Public String buildRequest(Builder builder) 
    { 
     doSomething(); 
     doMoreStuff(); 
     builder.build(); 
     doAfterStuff(); 
    } 

    // Command pattern 
    class BTypeBuilder implements Builder 
    { 
     String name, age, sex; 

     // Constructor here 

     void build() 
     { 
      // Do your stuff here 
     } 
    } 

    class ATypeBuilder implements Builder 
    { 
     String pin, amount; 

     // Constructor here 

     void build() 
     { 
      // Do your stuff here 
     } 
    } 

    public interface Builder 
    { 
     void build(); 
    } 
+0

Me gusta su solución. Pero creo que expone el BTypeBuilder() a un cliente. Lo que significa que el cliente debe conocer todos los diferentes tipos de constructores. ¿No es ese 'acoplamiento cerrado'? – sarahTheButterFly

+0

Podría introducir algún tipo de Builder-Factory. Un método de fábrica estático debería ser suficiente y oculta todos los diferentes constructores. Depende de lo que hagas. Si esto es parte de su API pública, el esfuerzo es razonable. Si no es así, no llegaría tan lejos. Por cierto: si te gusta la respuesta, recíbela;) – atamanroman

+0

¡Jaja ... acaba de votar tu voto! Gracias por responder mi pregunta. ;) – sarahTheButterFly

0

Además de otras respuestas, esto también podría ser útil para usted (si sólo quiere plugin de su método, no usar sus parámetros de 'antes' y 'después' de métodos)

interface Function0<R> { 
    R apply(); 
} 

public void performOperation(Function0<Void> operation) { 
    doSomething(); 
    doBeforeStuff(); 
    operation.apply(); 
    doAfterStuff(); 

} 

entonces se podría utilizar de esta manera,

final RequestBuilder builder = new RequestBuilder(); 
    performOperation(new Function0<Void>() { 
     public Void apply() { 
      builder.buildATypeRequest("1234", "2445"); 
      return null; 
     } 
    }); 

    performOperation(new Function0<Void>() { 
     public Void apply() { 
      builder.buildBTypeRequest("1234", "2445", "1234"); 
      return null; 
     } 
    }); 
0

en lugar de enviar una larga parámetro La lista eter simplemente inserta todos los parámetros en un mapa y envía ese mapa como argumento.

+0

Hmmm..Si el tamaño de la lista de parámetros es menor que 6 (¿o 4?), Entonces está bien. En realidad es mejor que empujarlos en un mapa, creo. ¿Cómo sabe su usuario qué poner en el mapa? – sarahTheButterFly

+0

¿De qué sirve esto? Debe agregar una nueva validación porque ya no puede decir si el mapa contiene objetos de ajuste. Sería mejor introducir algún tipo de clase de Persona, que podría agrupar nombre, sexo y edad. Si tienes muchos params, intenta introducir fábricas o constructores. Pero esto no tiene nada que ver con la pregunta inicial. – atamanroman

Cuestiones relacionadas