提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

装饰器设计模式平时使用的场景比较少,比较经典当然就是类似饮料的加料电商系统的优惠活动计算价格。我用C#实现了这两种场景,供大家相互学习。我理解的这个模式的主要目的就是对于原代码无侵入而且可以完成功能的扩展,还有就是由客户端(调用方)自行决定如何对于原类型装配新功能

一、饮料加料

  • 原逻辑代码:饮料抽象类以及实现抽象类的浓缩咖啡(什么都没加,价格10元)。后续我们就是要对于这杯浓缩咖啡进行加料(加牛奶,加糖),然后价格也会不同。
 public abstract class Beverage
    {
        public abstract string GetDescription();
        public abstract double Cost();
    }

    public class Espresso : Beverage
    {
        public override double Cost()
        {
            return 10;
        }

        public override string GetDescription()
        {
            return "浓缩咖啡";
        }
    }
  • 定义一个调味的装饰器抽象类CondimentDecorator,这个类集成饮料的抽象类,并且要求子类传入饮料实例,也就是后续子类实现中就会在这个饮料实例的基础上执行装饰操作。这里别晕,这个Beverage之所以要抽象类存储只是为了封装,其实子类自己存也可以,就是代码重复了
 public abstract class CondimentDecorator : Beverage
    {
        protected Beverage beverage;
        public CondimentDecorator(Beverage beverage)
        {
            this.beverage = beverage;
        }
    }
  • 加牛奶的装饰器。就是传进来一个饮料实例,保存起来,然后实现饮料的价格计算方法和原料显示的方法。只是要注意的是你装饰肯定是要在原有基础上装饰,所以你加牛奶的价格之前肯定得得到原来价格是多少,原料那个方法也是同理
 public class Milk : CondimentDecorator
    {
        public Milk(Beverage beverage) : base(beverage)
        {
        }

        public override double Cost()
        {
            return this.beverage.Cost() + 10;
        }

        public override string GetDescription()
        {
            return this.beverage.GetDescription() + " " + "牛奶";
        }
    }
  • 加糖的类似加牛奶的
  public class Sugar : CondimentDecorator
    {
        public Sugar(Beverage beverage) : base(beverage)
        {
        }

        public override double Cost()
        {
            return this.beverage.Cost() + 5;
        }

        public override string GetDescription()
        {
            return this.beverage.GetDescription() + " " + "糖";
        }
    }
  • 客户端(调用方)
    1、先整个原味的就是浓缩咖啡
    2、加牛奶定义一个牛奶装饰器实例,在原味浓缩咖啡的基础上加牛奶,所以之前的实例肯定要传进去啊,加糖同理。
 			var espresso=new Espresso();

              //加牛奶
              var hasMilk=new Milk(espresso);
              //加两份糖
              var hasSugar = new Sugar(new Sugar(hasMilk));

              Console.WriteLine(hasSugar.GetDescription());
              Console.WriteLine(hasSugar.Cost());

              Console.ReadKey();

2、面向切换编程示例代码

我想在UserService的GetUserName方法执行之前打印个日志,当然你可以可以整个比如给GetUserName整个try catch捕获异常等

  #region Services

    public interface IUserService
    {
        string GetUserName();
    }

    public class UserService : IUserService
    {
        public string GetUserName()
        {
            return "zhangsan";
        }
    }
    #endregion

    #region Decorator

    public interface IUserServiceDecorator : IUserService
    { }

    public class UserServiceLogDecorator : IUserServiceDecorator
    {
        private readonly IUserService userService;

        public UserServiceLogDecorator(IUserService userService)
        {
            this.userService = userService;
        }

        public string GetUserName()
        {
            Console.WriteLine("GetUserName被调用...");
            return userService.GetUserName();
        }
    }

    #endregion

调用

 IUserService userService=new UserService();
              var userServiceLogDecorator=new UserServiceLogDecorator(userService);
              Console.WriteLine(userServiceLogDecorator.GetUserName());

              Console.ReadKey();

3、电商 满减/打折

 public abstract class BaseCaculator
    {
        public abstract double Caculate();
    }
    public class Caculator : BaseCaculator
    {
        public override double Caculate()
        {
            return 100;
        }
    }

    public abstract class BaseDiscountCalculator : BaseCaculator
    {
        protected BaseCaculator baseCaculator;
        protected BaseDiscountCalculator(BaseCaculator baseCaculator)
        {
            this.baseCaculator = baseCaculator;
        }

        protected double OriginalPrice { get { return this.baseCaculator.Caculate(); } }
    }

    //满减活动
    public class FullDiscount : BaseDiscountCalculator
    {
        private readonly double max;
        private readonly double reduce;

        public FullDiscount(BaseCaculator baseCaculator, double max, double reduce) : base(baseCaculator)
        {
            if (reduce >= max)
                throw new ArgumentException("兄弟,不带这么玩的...");

            this.max = max;
            this.reduce = reduce;
        }

        public override double Caculate()
        {
            double price = this.OriginalPrice;
            if (price >= max)
                price -= reduce;
            return price;
        }
    }

    //打折
    public class OnSale : BaseDiscountCalculator
    {
        private double discountRate;

        public OnSale(BaseCaculator baseCaculator, double discountRate) : base(baseCaculator)
        {
            if (discountRate < 0.3)
                throw new ArgumentException("最多打三折");
            this.discountRate = discountRate;
        }

        public override double Caculate()
        {
            double price = this.OriginalPrice;
            return price * discountRate;
        }
    }

调用

  BaseCaculator caculator = new Caculator();
            //Console.WriteLine("没有优惠的价格:"+caculator.Caculate());

            //满100 减50
            BaseDiscountCalculator discountCalculator = new FullDiscount(caculator, 100, 50);
            //打五折
            BaseDiscountCalculator discountCalculator1 = new OnSale(discountCalculator, 0.5);

            Console.WriteLine("最终价格:" + discountCalculator1.Caculate());

            Console.ReadKey();

相信各位大佬能看懂,后面两个例子就不啰嗦了

更多推荐