2010-01-14 18 views
10

Tenemos un conjunto de clases que se derivan de un conjunto común de interfaces de tal manera queCodificación de mí mismo en una esquina

IFoo-> BasicFoo, ReverseFoo, ForwardFoo 
IBar -> UpBar, DownBar, SidewaysBar 
IYelp -> Yip, Yap, Yup 

el que el constructor para las miradas del Foo como Foo(IBar, IYelp) Estos artículos se utilizan en todo el proyecto.

Existe otra clase que tiene un método cuya firma es public double CalcSomething(IFoo, IAnotherClass) que se aplica en algún momento a todos y cada uno de los Foo. Hemos recibido una solicitud desde arriba de que una composición de objeto particular, digamos un BasicFoo(UpBar,Yip), usa un algoritmo diferente al encontrado en CalcSomething.

Mi primer instinto fue decir que cambiemos la interfaz IFoo para que podamos mover la lógica al nivel de clase Foo, cambiar el constructor a Foo(IBar, IYelp, IStrategy) y luego hacer que los objetos Foo encapsulen esta lógica. Desafortunadamente, también nos han dicho que el diseño de la arquitectura estipula que no habrá dependencias entre IFoo, sus implementaciones y IAnotherClass. Ellos son inflexibles sobre esto.

Ok, claro, entonces pensé que podría usar un patrón de visitante pero ... ¿cómo? El objetivo de hacer la composición fue que ninguna otra clase pudiera ver los detalles de la implementación. ¿Reflexión para mirar dentro de los objetos, rompiendo por completo la encapsulación? Oh diablos, no.

Así que he venido aquí porque estoy perdido. ¿Alguien tiene alguna sugerencia de cómo podríamos tratar un caso especial de una de las composiciones sin modificar la composición o romper la encapsulación? Tiene que haber una solución simple que estoy pasando por alto.

Editar:

Eliminado comienzo infractor. Cambiado "manejado especialmente" en un significado más descriptivo.

+9

Nunca falla: cuando una pregunta comienza tratando de justificar que no se publique el código, el intento resultante de evitar publicar el código hace que todo el lío sea casi imposible de entender. – delfuego

+0

eliminado la parte ofensiva – wheaties

+0

¿Puedes aclarar a qué te refieres con "tratado de manera especial"? –

Respuesta

3

Un CalculationFactory que elige un algoritmo adecuado en función del tipo de IFoo usted proporciona resolvería el problema (a costa de un condicional):

interface ICalcSomethingStrategy { 
    public double CalcSomething(IFoo, IAnotherClass); 
} 

CalcSomethingStrategyFactory { 
    ICalcSomethingStrategy CreateCalcSomethingStrategy(IFoo foo) { 
     // I'm not sure whether this is the idiomatic java way to check types D: 
     if (foo.Bar instanceof UpBar && foo instanceof Yip) { 
      return new UnusualCalcSomethingStrategy(); 
     } else { 
      return new StandardCalcSomethingStrategy(); 
     } 
    } 
} 
+0

Estábamos discutiendo si esto podría lograr lo que estamos tratando de hacer. No vemos otra forma de utilizar el reflejo para llegar al fondo de cómo dividir las cosas. – wheaties

+0

Aunque el acoplamiento es más ajustado, puede ver esto en términos de darles a los clientes un Contexto desde el que llamar a 'calcSomething()': http://en.wikipedia.org/wiki/Strategy_pattern#Java – trashgod

1

No hay manera de calcSomething para no tener los conocimientos necesarios para hacer el comportamiento "especial", pero aparte de eso, puede mantener la mayor parte de su encapsulación de esta manera.

Cree una interfaz de marcador IQualifyForSpecialTreatment que se extiende IFoo. Extienda BasicFoo a SpecialBasicFoo y haga que implemente IQualifyForSpecialTreatment.


    interface IQualifyForSpecialTreatment extends IFoo { 
    } 
    class SpecialBasicFoo extends BasicFoo implements IQualifyForSpecialTreatment { 
     ... 
    } 

A continuación, puede añadir otro sabor de calcSomething:


    calcSomething (IQualifyForSpecialTreatment foo, IAnotherClass whatever) { 
     ... perform "special" variant of calculation 
    } 
    calcSomething (IFoo foo, IAnotherClass whatever) { 
     ... perform "normal" variant of calculation 
    } 
3

En el espíritu de Kiss me gustaría añadir un método isSpecial() para IFoo, y usar eso para decidir qué algoritmo a utilizar en CalcSomething().

Esto supone que este es el único caso especial.

+0

+1 de acuerdo, el El enfoque de fábrica que sugerí probablemente sea más pesado de lo que debería ser si se trata de un asunto de una sola vez. –

+0

+1 de hecho. Simple, ordenado y suficiente. Si se infringe su supuesto de "único caso especial", isSpecial() podría refactorizarse para devolver un valor de "algoritmo de cálculo para aplicar". – CPerkins

Cuestiones relacionadas