上一篇我们完成了策略模式以及工厂模式的添加,已经成功将策略的选择从消费者中分离出来,但是在工厂中仍然需要使用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%,为什么呢,因为我们发现区间的问题很好解决,甚至使用属性就可以。但是新增加的策略需要修改工厂进行添加类型,这样就不符合我们的开闭原则,所以我们在下章解决该问题。
转载请标明出处。