C# 去除if-else以及子类管理 (中)利用特性限制策略条件

上一篇我们完成了策略模式以及工厂模式的添加,已经成功将策略的选择从消费者中分离出来,但是在工厂中仍然需要使用if else进行策略的筛选,为了解决这个问题我们引入一些新的东西:特性。

特性大家可以理解为和属性差不多的东西,特性本质是一个类,可以给其他的对象赋予属性。这里我不对特性进行过多说明,大家可以参考https://blog.csdn.net/long2006sky/article/details/1629075

在我们这次的例子中是以价格作为筛选策略的条件,也就是所每一个策略都拥有自己的价格区间,那么我们可以利用特性进行区间的限定操作,我们编写一个价格区间的特性类。

[AttributeUsage(AttributeTargets.Class)]//限定由于修饰类
public class PriceAttribute : Attribute
{
    public float Max { private set; get; }
    public float Min { private set; get; }

    public PriceAttribute(int min = -1, int max = 999999)
    {
        Max = max;
        Min = min;
    }
}

有了这个我们就可以给每一个策略添加上下限的特性

[Price(0,1000)]//特性命名中的Attribute可以省略
public class PublicVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price;
    }
}

[Price(1000,2000)]
public class JuniorVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price * 0.9f;
    }
}

策略拥有了特性之后我们在工厂中对特性进行读取

using System;

public class VipStrategyFactory
{
    private static VipStrategyFactory _instance;

    public static VipStrategyFactory Instance
    {
        get
        {
            if (_instance == null)
                _instance = new VipStrategyFactory();
            return _instance;
        }
    }

    //改写获取方法,利用特性筛选
    public IVipStrategy GetVipStrategy(Consumer consumer)
    {
        var totalConsume = consumer.TotalConsume;
        Type[] types =
        {
            typeof(PublicVipStrategy),
            typeof(JuniorVipStrategy)
        };
        foreach (var type in types)
        {
            var att = GetAttribute(type);
            if (att == null) continue;
            if ((att.Min <= totalConsume) && (totalConsume < att.Max))
                return (IVipStrategy) Activator.CreateInstance(type);
        }
        return new PublicVipStrategy();
    }

    private PriceAttribute GetAttribute(Type t)
    {
        var atts = t.GetCustomAttributes(typeof(PriceAttribute), true);
        if ((atts == null) || (atts.Length <= 0)) return null;
        foreach (PriceAttribute att in atts)
        {
            return att;
        }
        return null;
    }
}

改写完成以后我们可以看到已经去除掉if else的选择了,会根据特性区间进行自动筛选策略。如果需要添加新的Vip策略,直接继承基类,并且赋予特性区间范围即可。如高级会员

[Price(2000, 3000)]
public class SeniorVipStrategy : IVipStrategy
{
    public float GetExtenditure(float price)
    {
        return price*0.8f;
    }
}

注意修改工厂中Type数组,添加该会员的类型

        Type[] types =
        {
            typeof(PublicVipStrategy),
            typeof(JuniorVipStrategy),
            typeof(SeniorVipStrategy)
        };

我们看下消费情况

namespace Assets.Demo01.Strategy
{
    public class ContextView
    {
        public void Main()
        {
            var consumer = new Consumer();
            consumer.Buy(1000);
            consumer.Buy(1000);
            consumer.Buy(1000);
        }
    }
}

这里我们看到我们准备分三次购买价值1000金的商品,第二次我们是初级会员打折扣了,第三次的时候为什么没有打折扣呢,看程序,第二次我们实际只消费的900元,也就是目前共消费1900元,仍然处于初级会员状态,所以下一次消费仍然是900,我们想要第三次消费可以享受高级会员的优惠,可以适当提高第二次的消费如

namespace Assets.Demo01.Strategy
{
    public class ContextView
    {
        public void Main()
        {
            var consumer = new Consumer();
            consumer.Buy(1000);
            consumer.Buy(2000);
            consumer.Buy(2800);
        }
    }
}

第三次成功享受八折优惠。

目前为止已经完成70%,为什么呢,因为我们发现区间的问题很好解决,甚至使用属性就可以。但是新增加的策略需要修改工厂进行添加类型,这样就不符合我们的开闭原则,所以我们在下章解决该问题。

转载请标明出处。

你可能感兴趣的:(技术文档)