客户类的装饰器模式

时间:2019-05-28 09:36:07

标签: c# design-patterns decorator

假设我有一个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 :(得分:0)

我认为装饰器不是您要寻找的模式。

此外,您的代码似乎不是Decorator模式的实现。您没有在唯一的功能上添加任何功能。您只需覆盖它。但是,添加到现有功能的是Decorator模式的全部意义所在。

我的方法将是状态/策略模式。有不同种类的奖励。客户有一个或多个。这些奖励可以共享一个公共界面并提供不同的实现。客户(或子类或复合对象RewardedCustomer)应持有这些奖励的列表或地图。

答案 1 :(得分:0)

不要以为装饰器模式可以实现您想要的功能。装饰器在原始类的基础上添加了新功能。一个典型的Wiki示例将说,我们可以在画布顶部添加滚动条,菜单栏,覆盖和其他UI组件。因此,要创建适当的浏览器窗口,您将具有:

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

答案 2 :(得分:0)

我会使用访客模式,这对于您的情况非常理想。这样,您就可以很好地将针对不同客户类型的奖励计算分开,并针对所有受支持的奖励类型运行操作。

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