Декоратор Pattern вопрос C # / Java - PullRequest
5 голосов
/ 02 декабря 2010

Я просматривал эту статью в Википедии и не мог понять, как, черт возьми, это работает. Немного расстроенный неспособностью понять код, просто взглянув на него, я решил перенести код на c # (я .net, извините, ребята :)). Потребовались лишь небольшие изменения (наследование и расширение, база для супер и т. Д.) И запуск приложения. К моему удивлению, я получил следующий вывод:

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

Просто любопытно, может ли любой java-разработчик сказать мне, что здесь отличается и почему работает пример из Википедии (если, конечно, он работает так, как говорят).

    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;
    }
}

}

Ответы [ 4 ]

10 голосов
/ 02 декабря 2010

Да - методы являются виртуальными по умолчанию в Java, но не в C #.

Вы должны были получать предупреждения при компиляции кода, говоря о модификаторе «new». Это должно было дать вам подсказку. В настоящее время ваши Milk (и т. Д.) Методы скрывают или , затеняют те, что в CoffeeDecorator - их не вызывают полиморфно.

Вам нужно будет сделать методы CoffeeDecorator виртуальными с модификатором virtual, а затем явно переопределить их в Milk (и т. Д.) С модификатором override.

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

// In Milk
public override double getCost()
{
    return base.getCost() + cost;
}
2 голосов
/ 02 декабря 2010

Вы забыли объявить getCost и getIngredient virtual и использовать ключевое слово override в производных версиях.То, как вы это сделали, вы просто «перегружаете» методы.

0 голосов
/ 02 декабря 2010

Это немного подробный пример, но я думаю, что могу объяснить шаблон в 2 строки. Шаблон декоратора позволяет обернуть существующую реализацию интерфейса. Другое название шаблона - обертка.

Например, у вас есть интерфейс Foo:

interface Foo {
    public int foo();
}

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

SimpleFoo.foo () всегда возвращает 1;

Вот простой декаратор:

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

DoubleFoo.foo() украшает полезную нагрузку Foo. Результат умножается на 2.

Очевидно, что он также может заменить реализацию полезной нагрузки своей собственной реализацией. но это не классический случай паттерна.

Самым известным примером использования этого шаблона является IO в java: потоки, читатели и записывающие устройства являются оболочками. Например, BufferedReader добавляет функциональность для считывателя полезной нагрузки: он считывает данные в буферы.

0 голосов
/ 02 декабря 2010

Вы используете метод getCost () класса CoffeeDecorator, а не метод getCost () класса реализации. Вам нужно посмотреть, как вы переопределяете метод.

...