2010-12-02 17 views
5

Estaba mirando this artículo de la wikipedia, y no podía entender cómo diablos estaba funcionando. Un poco frustrado por no poder entender el código solo mirándolo, decidí portar el código a C# (soy .net, lo siento muchachos :)). Solo se necesitaban algunas modificaciones menores (hereda y extiende, base para súper, etc.) y ejecuta la aplicación. Para mi sorpresa, me dieron el siguiente resultado:Decorador Pregunta patrón C#/java

Cost: 1 Ingredient: Coffee 
Cost: 1 Ingredient: Coffee 
Cost: 1 Ingredient: Coffee 
Cost: 1 Ingredient: Coffee 

Sólo por curiosidad, puede cualquier dev java dime lo que es diferente aquí y por qué funciona el ejemplo wikipedia (si funciona como dicen que hace, por supuesto).

namespace ConsoleApplication1 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 

    Coffee sampleCoffee = new SimpleCoffee(); 
    Console.WriteLine("Cost: " + sampleCoffee.getCost() + " Ingredient: " + sampleCoffee.getIngredient()); 

     sampleCoffee = new Milk(sampleCoffee); 
     Console.WriteLine("Cost: " + sampleCoffee.getCost() + " Ingredient: " + sampleCoffee.getIngredient()); 

     sampleCoffee = new Sprinkles(sampleCoffee); 
     Console.WriteLine("Cost: " + sampleCoffee.getCost() + " Ingredient: " + sampleCoffee.getIngredient()); 

     sampleCoffee = new Whip(sampleCoffee); 
     Console.WriteLine("Cost: " + sampleCoffee.getCost() + " Ingredient: " + sampleCoffee.getIngredient()); 

    Console.ReadKey(); 

    } 
} 



//The Coffee Interface defines the functionality of Coffee implemented by decorator 
public interface Coffee 
{ 

    double getCost(); // returns the cost of coffee 

    String getIngredient(); //returns the ingredients mixed with coffee 
} 

//implementation of simple coffee without any extra ingredients 
public class SimpleCoffee : Coffee 
{ 

    double cost; 
    String ingredient; 

    public SimpleCoffee() 
    { 
     cost = 1; 
     ingredient = "Coffee"; 
    } 

    public double getCost() 
    { 
     return cost; 
    } 

    public String getIngredient() 
    { 
     return ingredient; 
    } 
} 



//abstract decorator class - note that it implements coffee interface 
abstract public class CoffeeDecorator : Coffee 
{ 

    protected Coffee decoratedCoffee; 
    protected String ingredientSeparator; 

    public CoffeeDecorator(Coffee decoratedCoffee) 
    { 
     this.decoratedCoffee = decoratedCoffee; 
     ingredientSeparator = ", "; 
    } 

public CoffeeDecorator() 
{ 

} 

    public double getCost() //note it implements the getCost function defined in interface Coffee 
    { 
     return decoratedCoffee.getCost(); 
    } 

    public String getIngredient() 
    { 
     return decoratedCoffee.getIngredient(); 
    } 
} 

//Decorator Milk that mixes milk with coffee 
//note it extends CoffeeDecorator 
public class Milk : CoffeeDecorator 
{ 

    double cost; 
    String ingredient; 

    public Milk(Coffee decoratedCoffee) : base(decoratedCoffee) 
    { 
     cost = 0.5; 
     ingredient = "Milk"; 
    } 

    public double getCost() 
    { 
     return base.getCost() + cost; 
    } 

    public String getIngredient() 
    { 
     return base.getIngredient() + base.ingredientSeparator + ingredient; 
    } 
} 

//Decorator Whip that mixes whip with coffee 
//note it extends CoffeeDecorator 
public class Whip : CoffeeDecorator 
{ 

    double cost; 
    String ingredient; 

public Whip(Coffee decoratedCoffee) 
    : base(decoratedCoffee) 
    { 
     cost = 0.7; 
     ingredient = "Whip"; 
    } 

    public double getCost() 
    { 
     return base.getCost() + cost; 
    } 

    public String getIngredient() 
    { 
     return base.getIngredient() + base.ingredientSeparator + ingredient; 
    } 
} 

//Decorator Sprinkles that mixes sprinkles with coffee 
//note it extends CoffeeDecorator 
public class Sprinkles : CoffeeDecorator 
{ 

    double cost; 
    String ingredient; 

    public Sprinkles(Coffee decoratedCoffee) : base(decoratedCoffee) 
    { 

     cost = 0.2; 
     ingredient = "Sprinkles"; 
    } 

    public double getCost() 
    { 
    return base.getCost() + cost; 
    } 

    public String getIngredient() 
    { 
    return base.getIngredient() + base.ingredientSeparator + ingredient; 
    } 
} 

} 
+0

No sé C#. Pero parece que no anulas tus métodos. –

+0

aquí el artículo de msdn sobre http://msdn.microsoft.com/en-us/library/ms173152%28VS.80%29.aspx –

Respuesta

10

Sí - los métodos son virtuales por defecto en Java, pero no en C#.

Debería haber recibido advertencias al compilar su código, hablando sobre el "nuevo" modificador. Eso debería haberte dado una pista. Actualmente sus métodos Milk (etc) son que ocultan o sombreados en CoffeeDecorator - no se llaman polimórficamente.

Se necesitaría para hacer que los métodos CoffeeDecorator virtual con el modificador virtual, y luego anular de forma explícita en Milk (etc) con el modificador override.

// In CoffeeDecorator 
public virtual double getCost() 
{ 
    return decoratedCoffee.getCost(); 
} 

// In Milk 
public override double getCost() 
{ 
    return base.getCost() + cost; 
} 
+0

Nooo ... Jon, eras 10 segundos más rápido que yo: '( – Hinek

+0

aagghh.debería haber mirado el compilador :). no sabía que por defecto todo es virtual en Java. lo que me lleva a otra pregunta ... ¿puedes hacer que los métodos sean "no" virtuales en Java? –

+1

@ Daniel Perez, puedes declararlo 'final'. –

2

se le olvidó declarar getCost y getIngredient virtual y el uso de la palabra clave en los override verions derivados. De la forma en que lo hiciste, simplemente "sobrecargas" los métodos.

+2

No es realmente una sobrecarga, es una sombra/escondite. –

0

Estás accediendo al método getCost() de CoffeeDecorator en lugar del método 'getCost() de la clase implementadora ... tienes que ver cómo estás redefiniendo el método.

0

Es un ejemplo poco detallado pero creo que puedo explicar el patrón en 2 líneas. El patrón decorador le permite ajustar la implementación existente de la interfaz. Otro nombre del patrón es envoltorio.

Por ejemplo, usted tiene interfaz de Foo:

interface Foo { 
    public int foo(); 
} 

class SimpleFoo implements Foo { 
    public int foo() { 
     return 1; 
    } 
} 

El SimpleFoo.foo() siempre devuelve 1;

Aquí es el decarator simple:

class DoubleFoo implements Foo { 
    private Foo payload; 
    public DoubleFoo(Foo payload) { 
     this.payload = payload; 
    } 
    public int foo() { 
     return 2 * payload.foo(); 
    } 
} 

DoubleFoo.foo() decora la carga útil Foo. Multiplica el resultado por 2.

Obviamente, también puede reemplazar la implementación de la carga por su propia implementación. pero no es un caso clásico del patrón.

El ejemplo más conocido de uso de este patrón es IO en java: las secuencias, los lectores y los escritores son todos envoltorios. Por ejemplo, BufferedReader agrega funcionalidad al lector de carga útil: lee datos en búferes.

Cuestiones relacionadas