经过一段时间对面向对象的学习,我借用了三层的思想对我的计算器进行了重构。
搭建三层架构、添加App.config配置文件:
首先新建一个空白的解决方案
然后右键解决方案添加类库,注意命名
这是我建好的类库
类库有了,接下来就要建立他们之间的引用了。展开类库,右键点击引用,点击项目,在要引用的类库前画对勾,确定
谁引用谁呢:我这里是UI引用BLL,BLL引用DAL的一个由外向里的过程的
ok,一个简单的三层到这里就搭好了。如果用实体的话还要添加一个modle,严格来说它不属于三层里的。我这里没那样用。
下面就可以把需要用到的类添加到对应的层下边了,如图:
因为是新建的空白解决方案,所以用到的东西都要手动添加。
本项目用到了配置文件:App.config,导入它的方法:右击相应的类库,添加,应用程序配置文件
还要用到程序的主函数,即Program.cs类,没有它程序运行会失败
这个新建一个同名的类,添加如下代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using UI;
namespace 计算器重构
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmCount());//new后边的窗体为你项目的启动窗体名
}
}
}
到这里,要用的东西就算齐活儿了。下面就该看具体程序了。
UI设计:
代码部分:
DAL:
加法运算,其他类似
namespace DAL
{
class AddOperate:Operate
{
public override double GetResult()
{
return Result += Num;
}
}
}
一个算式需要的成分:两个数字,一个运算符号,其中一个数字既作为本次运算的一个输出又作为下一步运算的输入,从而能实现连续运算,算符是用来处理数字的,单独拿了出来放在了上边
namespace DAL
{
public class Operate
{
//参与运算的数字
private double num;
public double Num
{
get { return num; }
set { num = value; }
}
//result既是这一步的结果又是参与下一步运算的数字
private double result;
public double Result
{
get { return result; }
set { result = value; }
}
//计算结果
public virtual double GetResult()
{
return result;
}
}
}
实例化算符算法的工厂
using System.Configuration;
using System.Reflection;
namespace DAL
{
public class OperateFactory
{
public static Operate CreateOperate(string oper)
{
Operate operate = null;
//读取算法类所在程序集
string dalName = ConfigurationManager.ConnectionStrings["DAL"].ToString();
//读取配置文件中的键,以获得算法类的值
string fullName = ConfigurationManager.AppSettings[oper];
//将程序集点儿类名拼接成字符串
string className = dalName + "." + fullName;
//通过反射实例化出拼接好的字符串点儿出来的类
Assembly assembly = Assembly.Load(dalName);
operate = (Operate)assembly.CreateInstance(className);
return operate;
}
#region switch语句。已优化成配置文件加反射形式,使类符合开闭原则,算法可扩展
//switch (oper)
//{
// case "+":
// operate = new AddOperate();
// break;
// case "-":
// operate = new MinusOperate();
// break;
// case "*":
// operate = new MutiplyOperate();
// break;
// case "/":
// operate = new DivideOperate();
// break;
//}
#endregion
}
}
BLL:
获取参与运算的数字
//截取参与运算的数字
//定义一个算符数组
char[] oper = new char[] { '+', '-', '*', '/' };
private string[] Num()
{
//通过算符将字符串中的数字切割出来
string headSign = _input.Substring(0, 1);
if (headSign == oper[0].ToString() || headSign == oper[1].ToString())
{
_input = 0 + _input;
}
string[] num = _input.Split(oper);
return num;
}
输入运算元素,返回运算结果,这个方法可以再封装的,我实现了一部分,还没弄好
//输入计算元素,返回运算结果
private string GetResult()
{
//接收截取字符串的结果
//避免对方法进行不必要的重复调用
string[] num = Num();
//初始化一个运算结果
double result = Convert.ToDouble(num[0]);
//初始化第一个数字长度
int len = 0;
Operate getResult;
//进行 n+1 方式的运算
for (int i = 0; i < num.Length - 1; i++)
{
//可再封装
//获取运算符
len = len + num[i].Length;
string m = _input.Substring(0, len + 1 + i);
string oper = m.Substring(m.Length - 1, 1);
//通过运算符确定对应的算法
getResult = OperateFactory.CreateOperate(oper);
//运算结果赋值进入运算体系
getResult.Result = result;
//参与运算的第i个数字赋值进入运算体系
getResult.Num = Convert.ToDouble(num[i + 1]);
//得到结果
result = getResult.GetResult();
}
return result.ToString();
}
处理计算结果并输出
//处理计算结果并输出
public string GetResult(string output)
{
string result = null;
try
{
if (_input == "")
{
output = "";
}
else
{
result = GetResult().ToString();
}
}
catch (Exception)
{
result = output;
}
return result;
}
UI:
将输入作为参数传入方法进行处理,并将结果显示
private void txtShow_TextChanged(object sender, EventArgs e)
{
lblResult.Text = new Count(txtShow.Text).GetResult(lblResult.Text);
}