C# 去除if-else以及子类管理 (下)利用反射获取策略的子类

本文探讨了如何通过反射改进C#中的策略模式,以动态获取和执行子类,避免if-else。虽然反射引入了一定的性能开销,但提供了更灵活的子类管理方式。在解决问题的过程中,作者发现接口基类无法获取具体类型,于是将接口改为抽象类,并要求子类重写方法。最后,添加新会员制度只需创建相应子类即可。

总体的解决方法全部使用反射,所以会消耗一定的性能,如果大家又更好的方法欢迎留言讨论

这一篇我们将解决手动编辑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);
    }
}

转载请标明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值