Шаблон декоратора для класса Customer - PullRequest
1 голос
/ 28 мая 2019

Предположим, у меня есть Customer класс.Клиент может иметь несколько видов очков лояльности.За одну акцию клиент может набрать Rewards.В другом клиент может собирать Miles.И не существует фиксированного количества видов очков лояльности, для которых построен Customer.Я уверен, что это общий случай использования.Является ли шаблон декоратора подходящим для приведенного ниже примера кода?

    public interface ICustomer
    {
        void Display();
    }

    public class SimpleCustomer : ICustomer
    {
        public void Display()
        {
            Console.WriteLine("I am simple customer");
        }
    }

    public abstract class CustomerDecorator : ICustomer
    {
        protected ICustomer customer;

        public CustomerDecorator(ICustomer customer)
        {
            this.customer = customer ?? throw new ArgumentNullException("customer");
        }

        public abstract void Display();
    }

    public class RewardsDecorator : CustomerDecorator
    {
        private int rewards;
        public RewardsDecorator(ICustomer customer, int rewards) : base(customer)
        {
            this.rewards = rewards;
        }

        public override void Display()
        {
            Console.WriteLine("Now I have " + rewards.ToString() + " rewards");
        }
    }

    public class MilesDecorator : CustomerDecorator
    {
        private int miles;
        public MilesDecorator(ICustomer customer, int miles) : base(customer)
        {
            this.miles = miles;
        }

        public override void Display()
        {
            Console.WriteLine("Now I have " + miles.ToString() + " miles");
        }
    }

Ответы [ 3 ]

0 голосов
/ 28 мая 2019

Не думайте, что шаблон Decorator делает то, что вы от него хотите.Декоратор добавляет новые функциональные возможности поверх оригинального класса.Типичный пример вики сказал бы, что мы можем добавить полосу прокрутки, строку меню, оверлеи и другие компоненты пользовательского интерфейса поверх холста.Таким образом, чтобы создать правильное окно браузера, у вас будет:

public class Canvas
public class ScrollableCanvas
public class OverlayedCanvas
etc.

, чтобы мы добавили больше функций к оригинальному Canvas.

Чтобы решить вашу проблему, у вас должно быть что-то вроде:

public abstract class LoyaltyProgramAccount {...}

public class RewardAccount extends LoyaltyProgramAccount {...}

public class MilesAccount extends LoyaltyProgramAccount {...}

И затем добавьте перечисление регистрации:

public enum LoyaltyProgramTypes {
    miles,
    reward,
}

и затем пусть пользователь будет:

public class Customer {

    private List<LoyaltyProgramTypes, LoyaltyProgramAccount> accounts;

    public void openAccount(LoyaltyProgramTypes type, LoyaltyProgramAccount account) {
        accounts.put(type, account);
    }
    ...
}
0 голосов
/ 30 мая 2019

Я бы использовал шаблон посетителей, это довольно идеально для вашей ситуации. Это позволит вам аккуратно разделить расчеты вознаграждений для разных типов клиентов и выполнять операции для всех поддерживаемых типов вознаграждений.

class Program
{
    static void Main(string[] args)
    {
        MilesCustomer customer = new MilesCustomer();
        ICustomerVisitor<int> visitor = new MilesCalculation(10);
        var miles = customer.Visit(visitor);
        visitor = new RewardsCalucation(100);
        var rewards = customer.Visit(visitor);
    }
}
public interface ICustomerVisitor<T>
{
    T Visit(SimpleCustomer cusomter);
    T Visit(RewardsCustomer cusomter);
    T Visit(MilesCustomer cusomter);
}

public abstract class Customer
{
    public Customer()
    {
        TotalMoneySpent = 10;
    }

    public int TotalMoneySpent { get; private set; }

    public abstract T Visit<T>(ICustomerVisitor<T> visitor);

    public virtual void Display()
    {
        Console.WriteLine("I am simple customer");
    }
}

public class RewardsCalucation : ICustomerVisitor<int>
{
    private int _rewardsPerDollar;

    public RewardsCalucation(int rewardsPerDollar) => _rewardsPerDollar = rewardsPerDollar;

    public int Visit(SimpleCustomer cusomter)
    {
        return 0;
    }

    public int Visit(RewardsCustomer cusomter)
    {
        return cusomter.TotalMoneySpent * _rewardsPerDollar;
    }

    public int Visit(MilesCustomer cusomter)
    {
        return 0;
    }
}

public class MilesCalculation : ICustomerVisitor<int>
{
    private int _milesPerDollar;
    public MilesCalculation(int milesPerDollar) => _milesPerDollar = milesPerDollar;
    public int Visit(SimpleCustomer cusomter)
    {
        return 0;
    }

    public int Visit(RewardsCustomer cusomter)
    {
        return 0;
    }

    public int Visit(MilesCustomer cusomter)
    {
        return cusomter.TotalMoneySpent * _milesPerDollar;
    }
}

public class SimpleCustomer : Customer
{
    public override T Visit<T>(ICustomerVisitor<T> visitor)
    {
        return visitor.Visit(this);
    }
}

public class RewardsCustomer : Customer
{
    public override T Visit<T>(ICustomerVisitor<T> visitor)
    {
        return visitor.Visit(this);
    }
}

public class MilesCustomer : Customer
{
    public override T Visit<T>(ICustomerVisitor<T> visitor)
    {
        return visitor.Visit(this);
    }
}
0 голосов
/ 28 мая 2019

Я не думаю, что Decorator - это тот шаблон, который вы ищете.

Кроме того, ваш код, похоже, не является реализацией шаблона Decorator.Вы не добавляете никакой функциональности к единственной функции.Вы просто переопределите это.Но добавление к существующей функции - вот что такое шаблон Decorator.

Мой подход - шаблон состояния / стратегии.Есть разные виды вознаграждений.И у клиента есть один или несколько из них.Эти награды могут иметь общий интерфейс и предоставлять разные реализации.Клиент (или подкласс или составной объект RewardedCustomer) должен иметь список или карту этих наград.

...