在学习设计模式的时候,其中有一种模式叫工厂模式,工厂模式里经典的案例就是设计一个计算器,在工厂模式里都是用
swith() ... case ...
来实例化类。并调用类里的方法
例:
每添加一种计算方法,那就要在 swith() ... case ... 里实例化该类,这样有一个步骤忘了,就计算不出来结果
所以我就想要是只要类的名字,然后通过这个名字实例化类出来,然后再调用类里计算的方法,
这样的话,我就只需要编写类的计算方法,然后把这个类的类名告诉程序,程序在计算时,通过
用户输入的计算符号(如+,-,*,/,√ )来进行选择用那个类进行计算,有了这个思路,但是这种方
法是否可行呢,有了反射,这个想法是肯定可以的,下面就是我用这种方式实的!
加法类
我这里用枚举去存,个人爱好!
结语:为什么要用反射,这样的好处就是我再添加其它运算类时,只需要继承BaseClass类,并自述自己是
用来做什么样的运算,即Symbol=“那种计算方式”,重写Calculation方法,并返回结果。实现计算类后,把
类名加 enum ClassName里面,就可以了,便于后期添加更多的计算类。
例:
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里面,就可以了,便于后期添加更多的计算类。