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

来源:互联网 发布:淘宝买托福答案被骗 编辑:程序博客网 时间:2024/06/10 10:34
在学习设计模式的时候,其中有一种模式叫工厂模式,工厂模式里经典的案例就是设计一个计算器,在工厂模式里都是用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里面,就可以了,便于后期添加更多的计算类。