C# 丢弃工厂模式,反射方式实现计算器

在学习设计模式的时候,其中有一种模式叫工厂模式,工厂模式里经典的案例就是设计一个计算器,在工厂模式里都是用 swith() ... case ... 来实例化类。并调用类里的方法
例:
switch (symbol)
            {
                case "+":
                    bc = new Add();
                    bc.Calculation(num1,num2);
                    break;
                case "-":
                     bc = new Sub();
                    bc.Calculation(num1, num2);
                    break;
                case "*":
                    bc = new Mul();
                    bc.Calculation(num1, num2);
                    break;
                case "/":
                    bc = new Div();
                    bc.Calculation(num1, num2);
                    break;
                default:
                    bc = new BaseClass();
                    bc.Calculation(num1, num2);
                    break;
            }

每添加一种计算方法,那就要在 swith() ... case ... 里实例化该类,这样有一个步骤忘了,就计算不出来结果

所以我就想要是只要类的名字,然后通过这个名字实例化类出来,然后再调用类里计算的方法,
这样的话,我就只需要编写类的计算方法,然后把这个类的类名告诉程序,程序在计算时,通过
用户输入的计算符号(如+,-,*,/,√ )来进行选择用那个类进行计算,有了这个思路,但是这种方
法是否可行呢,有了反射,这个想法是肯定可以的,下面就是我用这种方式实的!

定义一个基类BaseClass,里面包含了计算的符号和计算的方法

class BaseClass
    {
        /// <summary>
        /// 符号
        /// </summary>
        public string Symbol { get; set; }
 
        /// <summary>
        /// 计算方法
        /// </summary>
        /// <param name="a">其中一个值</param>
        /// <param name="b">另一个值</param>
        /// <returns></returns>
        public virtual float Calculation(float a, float b)
        {
            return 0;
        }
    }
接下来就是我们计算类,所有计算类都继承基类BaseClass
加法类
class Add : BaseClass
    {
        const string add = "+";
        public Add()
        {
            Symbol = add;
        }
        public override float Calculation(float a, float b)
        {
            return a + b;
        }
    }
减法类
class Sub : BaseClass
    {
        const string sub = "-";
        public Sub()
        {
            Symbol = sub;
        }
 
        public override float Calculation(float a, float b)
        {
            return a - b;
        }
    }
乘法类
class Mul : BaseClass
    {
        const string mul = "*";
        public Mul()
        {
            Symbol = mul;
        }
 
        public override float Calculation(float a, float b)
        {
            return a * b;
        }
    }
除法类
class Div : BaseClass
    {
        const string div = "/";
        public Div()
        {
            Symbol = div;
        }
        public override float Calculation(float a, float b)
        {
            if (0 == b)
            {
                return 0;
            }
 
            return a / b;
        }
    }
开方类
class Square:BaseClass
    {
        const string sub = "√";
        public Square()
        {
            Symbol = sub;
        }
        public override float Calculation(float a, float b)
        {
            return (float)Math.Sqrt(a);
        }
    }
定义好了计算类,现在要让程序知道,这些类叫什么名字,可以把它存在一个数组,链表,枚举里
我这里用枚举去存,个人爱好!
enum ClassName
    {
        Add,
        Sub,
        Mul,
        Div,
        Square
    }
现在计算类有了,类名也有了,接下来就是要实例化这些类,那就得用反射的原理了
/// <summary>
       /// 实例化ClassName里Add、Sub、Mul、Div、Square运算类
       /// </summary>
       /// <returns></returns>
       static List<object> InitBaseClass()
       {
           if (Enum.GetNames(typeof (ClassName)).Length == 0) return null;
 
           //定义BaseClass实例化
           List<object> bsList = new List<object>();
 
           // 获取当前方法的命名空间
           string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
 
           //实例化ClassName里Add、Sub、Mul、Div、Square运算类
           foreach (var name in Enum.GetNames(typeof (ClassName)))
           {
               Type type = Type.GetType(nameSpace + "." + name); //获取类型
               bsList.Add(Activator.CreateInstance(type)); //根据类型创建实例
           }
 
           return bsList;
       }
类实例出来后,当我输入5+5时,程序就要自己去匹配加法类的计算方法,然后返回结果
/// <summary>
        /// 计算结果
        /// </summary>
        /// <param name="bsObjects">有多少个运算类</param>
        /// <param name="symbol">什么符号</param>
        /// <param name="num1">计算的数字一</param>
        /// <param name="num2">计算的数字二</param>
        /// <returns></returns>
        static object CalcResult(List<object> bsObjects, string symbol, float num1, float num2)
        {
            if (bsObjects.Count == 0 || string.IsNullOrEmpty(symbol)) return null;
 
            object result = null;
 
            foreach (var intance in bsObjects)
            {
                //获取的值是什么符号
                var symbolValue = intance.GetType().GetProperty("Symbol").GetValue(intance, null);
                //要调用那个运算类的方法
                if (Convert.ToString(symbolValue) == symbol)
                {
                    //调用类里的Calculation方法所获得的返回值
                    result = intance.GetType().GetMethod("Calculation").Invoke(intance, new object[] {num1, num2});
                }
            }
 
            if (result == null) return "没有正确的运算符!";
 
            return result;
        }
最后就是调用
static void Main(string[] args)
        {
            //存储实例化的计算类,只实例化一次
            List<object> bsObjects = InitBaseClass();
 
            //开线程调用计算方法
            //new Thread(() =>
            //{
            //    Console.WriteLine(CalcResult(bsObjects, "+", 5, 80));
            //})
            //{IsBackground = true}.Start();
 
            //调用计算方法
            object result = CalcResult(bsObjects, "√", 3, 8);
            Console.WriteLine(result);
 
            Console.ReadKey();
        }

结语:为什么要用反射,这样的好处就是我再添加其它运算类时,只需要继承BaseClass类,并自述自己是
用来做什么样的运算,即Symbol=“那种计算方式”,重写Calculation方法,并返回结果。实现计算类后,把
类名加 enum ClassName里面,就可以了,便于后期添加更多的计算类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值