2012-01-24 10 views
8

Tengo la siguiente interfaz.¿Es este un decorador o un patrón de estrategia, o ninguno de los dos?

PowerSwitch.java

public interface PowerSwitch { 
    public boolean powerOn(); 
    public boolean powerOff(); 
    public boolean isPowerOn(); 
} 

La interfaz anterior debe consistir en el conjunto mínimo de métodos que cualquier otra funcionalidad se puede derivar de, para que sea tan fácil como sea posible para agregar implementaciones PowerSwitch adicionales.

me gustaría agregar funcionalidad a la interfaz PowerSwitch en tiempo de ejecución (lo decoradores lo hacen), mediante la creación de una clase que contiene una composición de una instancia de PowerSwitch y añade nuevos métodos, como los dos toggleOnOff() métodos abajo. De esa manera solo necesito implementar los dos métodos de alternar una vez y se aplicará a todas las implementaciones de PowerSwitch.

¿Esto se considera como una buena/mala práctica? Si es malo, ¿alguna otra recomendación?

Realmente no cumple con el patrón de decorador ya que agrega métodos adicionales. ¿Es un patrón de estrategia o un patrón de composición? ¿O tiene otro nombre de patrón? ¿Hay algo así como un "decorador de interfaz"?

PowerSwitchDecorator.java

public class PowerSwitchDecorator { 
    private PowerSwitch ps; 

    public PowerSwitchDecorator(PowerSwitch ps) { 
     this.ps = ps; 
    } 

    public void toggleOnOff(int millis) throws InterruptedException{ 
     powerOn(); 
     Thread.sleep(millis); 
     powerOff(); 
    } 

    public void toggleOnOff(){ 
    powerOn(); 
    powerOff(); 
    } 

    public boolean powerOn() { 
     return ps.powerOn(); 
    } 

    public boolean powerOff() { 
     return ps.powerOff(); 
    } 

    public boolean isPowerOn() { 
     return ps.isPowerOn(); 
    } 
} 
+5

¿Por qué no PowerSwitchDecorator implementar la interfaz PowerSwitch? Ciertamente podría ... – Ani

Respuesta

3

Esa es una buena práctica en el caso de que necesite para mejorar su instancia PowerSwitch en tiempo de ejecución. Te recomiendo que implementes la interfaz de PowerSwitch en el decorador. El otro nombre del patrón de decorador es el patrón de proxy.

Puede definir los métodos extendidos en otra interfaz que amplíe su interfaz PowerSwitch. Eso evitará tener una dependencia en el decorador cuando se necesiten llamar a estos métodos extendidos.

Extender una clase es una buena práctica cuando necesita mejorar o redefinir un comportamiento en la compilación.

+0

¡Gracias! Haré que el decorador implemente la interfaz de PowerSwitch – etxalpo

0

Sería realmente un decorador si el decorador también implementara la interfaz PowerSwitch. Yo caracterizaría esto como agregación de objetos.

7

Como es, cualquier código que quiere usar los métodos toggleOnOff(int) o toggleOnOff() va a necesitar una instancia de PowerSwitchDecorator, no PowerSwitch. Este tipo de derrotas el propósito de un decorador que debe ser transparente para el cliente.

Si desea que todas las implementaciones tengan estos métodos, debe incluirlos en la interfaz PowerSwitch.

Entonces, como sugiere @Ani, podría modificar la anterior PowerSwitchDecorator que se extienden PowerSwitch por lo que se puede hacer esto:

PowerSwitch switch = new PowerSwitchDecorator(new ConcretePowerSwitch()); 
switch.toggleOnOff(); 

Ahora usted tiene una variable de tipo PowerSwitch con las capacidades de la PowerSwitchDecorator 's.

EDITAR: Tenga en cuenta que solo debe usar un patrón establecido si satisface sus necesidades. Puede usar el enfoque que ha mostrado si le funciona. No es necesario conectarlo a un patrón específico.

¿Qué tipo de objeto quiere pasar? ¿Quieres métodos como éste en su API:

void connect(PowerSwitch powerSwitch, Appliance appliance); 

o métodos como este:

void connect(PowerSwitchDecorator powerSwitch, Appliance appliance); 

(lo siento, no son muy buenos ejemplos)

Si desea que el primero, entonces todos tendrán que 'decorar' manualmente su PowerSwitch solo para obtener un par de métodos de conveniencia. Puede ser conveniente para usted ahora, pero creo que será un inconveniente para los usuarios de su código y probablemente no se molesten con él. Si desea lo último, debe usar el tipo PowerSwitchDecorator en sus firmas de métodos, lo que significa que siempre se ocupa de PowerSwitchDecorator sy no PowerSwitch es sin formato.

+1

¿Pero no significa que necesito implementar métodos ficticios (toggleOnOff) en todas las implementaciones de powerswitch? y, además, si quiero agregar un nuevo método más adelante (digamos toggleOffOn) en Decorator, entonces necesito agregarlo a la interfaz de PowerSwitch y actualizar todas las implementaciones actuales de PowerSwitch (ya que no compilarán más). También podría ser el caso de que no tenga acceso a todas las implementaciones de PowerSwitch (podría ser parte de una interfaz de proveedor de servicios). – etxalpo

+1

Como etxalpo, no estoy de acuerdo. Simplemente haciendo que el decorador implemente la interfaz decorada, sigue siendo útil porque todos los clientes de un PowerSwitch pueden usar un PowerSwitchDecorator. Del mismo modo que todos los clientes de un lector pueden usar un BufferedReader de forma transparente. Esto no impide que el BufferedReader agregue sus propios métodos (readLine() por ejemplo) y que este patrón sea extremadamente útil. –

+0

Sí, eso es correcto. Probablemente desee una clase abstracta con métodos de alternancia básicos de los que hereden todas sus implementaciones. Entonces, si quieres una forma específica de alternar, podrías decorarla. Edité mi respuesta, espero que ayude;) –

0

No es ninguno de los patrones.

Un decorador tiene la intención de envolver un objeto y ampliar la funcionalidad existente haciendo que la interfaz sea transparente para el cliente. Un BufferedInputstream es un ejemplo. Tenga en cuenta que el Decorador debe implementar la misma interfaz que el Tipo que está envolviendo.

//Let Type be the interface that both the Decorator and DecoratedClass implements 
Type yourInstance = new Decorator(new DecoratedClass()); 

Nota la diferencia desde el Proxy-patrón, donde la intención principal es controlar el acceso a un objeto, no necesariamente envolviendo otro objeto. En este caso, también permitiría que el proxy implemente la misma interfaz.

+0

¿Quiere decir "Tenga en cuenta que ..." y "Tenga en cuenta la diferencia ..." cuando diga "No es que ..." y "No es la diferencia ..."? –

+0

Sí, perdón por el error tipográfico. ¡Gracias! –

0

Varios patrones a menudo se ven similares, la diferencia radica en la intención de su uso. Aquí hay un hilo más general sobre este tema: When and How Strategy pattern can be applied instead of decorator pattern?

Con su código, todavía no hay diferencia real. Parece una estrategia, ya que PowerSwitchDecorator simplemente está delegando el trabajo (es decir, el algoritmo) a un PowerSwitch. Si esa es su intención y existen PowerSwitches alternos alternando de diferentes maneras, el patrón de estrategia es su elección.

Si en su lugar tiene un conjunto de interruptores de encendido, cada uno mejorando el alternar de una manera leve (decorando el alternar) y estos interruptores de encendido pueden anidarse, entonces está implementando un decorador. Como se ha dicho antes, en este caso también necesita que los decoradores formen parte de la jerarquía de tipos.

0

Yo diría que no es ninguno de los patrones.

Decorator

El patrón decorador se utiliza para extender el comportamiento de una aplicación existente. Tome una ventana gráfica como ejemplo, es posible que desee tener una ventana que tenga barras de desplazamiento. A continuación, puede tener una clase como

public class ScrollBarsWindow : Window 
{ 
    private Window windowToDecorate; 
    public ScrollBarsWindow(Window windowToDecorate) 
    { 
     this.windowToDecorate = windowToDecorate; 
    } 

    public void Draw() 
    { 
     windowToDecorate.Draw(); 
     DrawScrollBars(); 
    } 

    public void DrawScrollBars() 
    { Draw the scroll bars } 
} 

El patrón de estrategia

El patrón de estrategia se utiliza para hacer cosas diferentes en función de la estrategia elegida. Digamos que estás haciendo un café.El que podría tener algo como:

public interface IMakeCoffeeStrategy 
{ 
    public Coffee MakeCoffee(); 
} 

public class CappuccinoStrategy : IMakeCoffeeStrategy 
{ 
    public Coffee MakeCoffee { make your cappuccion } 
} 

public class LatteStrategy : IMakeCoffeeStrategy 
{ 
    public Coffee MakeCoffee { make your latte } 
} 

public class Context 
{ 
    private IMakeCoffeeStrategy strategy; 
    public Context(IMakeCoffeeStrategy strategy) 
    { 
     this.strategy = strategy; 
    } 

    public Coffee MakeSomeCoffee() 
    { 
     return strategy.MakeCoffee(); 
    } 
} 

y utilizarlo como

public class MyCoffeeMachine 
{ 
    public Coffee MakeCoffee(CoffeeType coffeeType) 
    { 
     if(coffeeType == CoffeeType.Latte) 
      return new Context(new LatteStrategy()).MakeSomeCoffee(); 
     else if(coffeeType == CoffeeType.Cappuccino) 
      return new Context(new CappuccinoStrategy()).MakeSomeCoffee(); 

     ... 
    } 
} 

Lea los siguientes enlaces para obtener más información:

0

Su clase PowerSwitchDecorator no es decoradora. Su aplicación está cerca de Strategy_pattern a pesar de que los comandos se asemejan Command_pattern

En Decorator patrón, Decorator realidad implementa la interfaz (es decir Component) y su clase no está haciendo lo mismo.

Tenga una mirada en diagrama de clases

enter image description here

En el diagrama anterior, Component es una interfaz. Decorator implementa la interfaz Component y contiene la interfaz con Composition. Mire la variable miembro - component.

se refieren a estas preguntas para una mejor comprensión:

Decorator Pattern for IO

Real World Example of the Strategy Pattern

Cuestiones relacionadas