总体的解决方法全部使用反射,所以会消耗一定的性能,如果大家又更好的方法欢迎留言讨论
这一篇我们将解决手动编辑Type数组的问题,直接修改工厂类。
using System;
using System.Collections.Generic;
using System.Reflection;
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;
var types = GetVipStrategy();
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;
}
private Type[] GetVipStrategy()
{
var temp = Assembly.GetCallingAssembly().GetTypes();
var typeFullName = typeof(IVipStrategy);
var list = new List<Type>();
foreach (var type in temp)
{
var baseType = type.BaseType;
while (baseType != null)
{
if (baseType == typeFullName)
{
list.Add(type);
break;
}
baseType = baseType.BaseType;
}
}
return list.ToArray();
}
}
这样就可以获取了,运行观察结果

我们发现结果没有进行任何折扣,全部执行的大众会员策略,很明显是我们最后添加的子类获取不正确,下断点看一下

可以看到类型获取到了,那么继续向下走

这里我们观察到,消费策略的基类是Object,并不是我们的接口基类,我又回去看了下反射,发现接口基类是获取不到具体的类型的,所以我将接口的基类更改为抽象类,这时注意子类中的方法需要添加上override
public abstract class IVipStrategy
{
public abstract float GetExtenditure(float price);
}
运行观察效果

成功获取,如果需要添加新的会员制度,只需要编写新的子类就可以实现了。
完成工程:
PriceAttribute.cs
using System;
[AttributeUsage(AttributeTargets.Class)] //限定由于修饰类
public class PriceAttribute : Attribute
{
public PriceAttribute(int min = -1, int max = 999999)
{
Max = max;
Min = min;
}
public float Max { private set; get; }
public float Min { private set; get; }
}
IVipStrategy.cs
public abstract class IVipStrategy
{
public abstract float GetExtenditure(float price);
}
PublicVipStrategy.cs
[Price(0,1000)]
public class PublicVipStrategy : IVipStrategy
{
public override float GetExtenditure(float price)
{
return price;
}
}
JuniorVipStrategy.cs
[Price(1000,2000)]
public class JuniorVipStrategy : IVipStrategy
{
public override float GetExtenditure(float price)
{
return price * 0.9f;
}
}
SeniorVipStrategy .cs
[Price(2000, 3000)]
public class SeniorVipStrategy : IVipStrategy
{
public override float GetExtenditure(float price)
{
return price*0.8f;
}
}
VipStrategyFactory.cs
using System;
using System.Collections.Generic;
using System.Reflection;
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;
var types = GetVipStrategy();
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 static 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;
}
private Type[] GetVipStrategy()
{
var temp = Assembly.GetCallingAssembly().GetTypes();
var typeFullName = typeof(IVipStrategy);
var list = new List<Type>();
foreach (var type in temp)
{
var baseType = type.BaseType;
while (baseType != null)
{
if (baseType == typeFullName)
{
list.Add(type);
break;
}
baseType = baseType.BaseType;
}
}
return list.ToArray();
}
}
Consumer.cs
using UnityEngine;
public class Consumer
{
private float _price;
public float TotalConsume { private set; get; }
private IVipStrategy _vipStrategy;
public Consumer()
{
_vipStrategy = new PublicVipStrategy();
}
public void Buy(int price)
{
_price = GetConsume(price);
Console.WriteLine("消费了 : " + _price);
TotalConsume += _price;
}
private float GetConsume(int price)
{
_vipStrategy = VipStrategyFactory.Instance.GetVipStrategy(this);
return _vipStrategy.GetExtenditure(price);
}
}
ContextView.cs
public class ContextView
{
public void Main()
{
var consumer = new Consumer();
consumer.Buy(1000);
consumer.Buy(2000);
consumer.Buy(2800);
}
}
转载请标明出处。
本文探讨了如何通过反射改进C#中的策略模式,以动态获取和执行子类,避免if-else。虽然反射引入了一定的性能开销,但提供了更灵活的子类管理方式。在解决问题的过程中,作者发现接口基类无法获取具体类型,于是将接口改为抽象类,并要求子类重写方法。最后,添加新会员制度只需创建相应子类即可。
1081

被折叠的 条评论
为什么被折叠?



