28 dezembro, 2015 0 Comentários AUTOR: elemarjr CATEGORIAS: Sem categoria

Decorator Design Pattern using lambdas (C# version)

Tempo de leitura: 1 minuto

Olá.

Minha proposta, nesse post, é compartilhar uma implementação em C# para o código Java disponível aqui.

Recomendo fortemente que você veja o post original antes de continuar a leitura aqui.

Código Java (original):

public interface Pizza {
    String bakePizza();

    static Pizza withChickenTikka(Pizza pizza) {
        return new Pizza() {
            @Override
            public String bakePizza() {
                return pizza.bakePizza() + " with chicken";
            }
        };
    }

    static Pizza withProsciutto(Pizza pizza) {
        return new Pizza() {
            @Override
            public String bakePizza() {
                return pizza.bakePizza() + " with prosciutto";
            }
        };
    }
}

Código C#:

interface IPizza
{
    string BakePizza();
}

class GenericPizza : IPizza
{
    private readonly Func<string> _bakePizzaImpl;

    public GenericPizza(Func<string> bakePizzaImpl)
    { _bakePizzaImpl = bakePizzaImpl; }

    public string BakePizza()
    { return _bakePizzaImpl(); }
}

static class Pizza
{
    public static IPizza WithChickenTikka(IPizza pizza)
    {
        return new GenericPizza(() => pizza.BakePizza() + " with chicken");
    }

    public static IPizza WithProsciutto(IPizza pizza)
    {
        return new GenericPizza(() => pizza.BakePizza() + " with prosciutto");
    }
}

Senti falta da possibilidade de escrever tipos anônimos que implementem a interfaces em C#, mas ...

Código Java:

public class PizzaDecorator {
    private final Function<Pizza, Pizza> toppings;

    private PizzaDecorator(Function<Pizza, Pizza>... desiredToppings) {
        this.toppings = Stream.of(desiredToppings)
                .reduce(Function.identity(), Function::andThen);

    }

    public static String bakePizza(Pizza pizza, Function<Pizza, Pizza>... desiredToppings) {
        return new PizzaDecorator(desiredToppings).bakePizza(pizza);
    }

    private String bakePizza(Pizza pizza) {
         return this.toppings.apply(pizza).bakePizza();
    }
}

Aqui resolvi fazer uma pequena modificação de design.

Código C#:

static class Function
{
    public static Func<T, T> AndThen<T>(this Func<T, T> func, Func<T, T> andThen)
    {
        return (input) => andThen(func(input));
    }
}

static class PizzaExtensions
{
    public static IPizza DecorateWith(
        this IPizza pizza,
        params Func<IPizza, IPizza>[] desiredToppings
        )
    {
        var func = desiredToppings
            .Aggregate(Function.AndThen);

        return func(pizza);
    }
}

class Program
{
    static void Main(string[] args)
    {
        //var finishedPizza = new BasicPizza()
        //     .DecorateWith(Pizza.WithChickenTikka)
        //     .DecorateWith(Pizza.WithProsciutto);

        var finishedPizza = new BasicPizza()
            .DecorateWith(
                Pizza.WithChickenTikka,
                Pizza.WithProsciutto
            );

        Console.WriteLine(finishedPizza.BakePizza());
    }
}

Repare que .NET, diferente do Java 8, não fornece um método direto de composição (AndThen).

Era isso.

Enviar um comentário