【机房重构】模板方法—让组合查询变简单

组合查询是我们在开发机房收费系统中公认比较难实现的模块,但是我告诉你有一种方法可以让组合查询变得很简单,你想知道吗?听我慢慢道来。
在准备开发这个功能的时候,我发现它的复用程度很高:界面一样,控件布局一样,查询方式也一样,只不过是我查询的具体内容之间有些差别。仔细一想,这不就跟模板方法一样吗。
模板方法:定义一个操作中的算法的骨架(组合查询父窗体),而将一些步骤延迟到子类中(子窗体独有的属性)。
知道了这些之后,组合查询功能就有了,我们首先要建立一个组合查询父窗体模板:
【机房重构】模板方法—让组合查询变简单
简单代码实现:

U层

        /// <summary>
        /// 定义一个个虚方法  GetDbTableName 在子窗体重写
        /// </summary>
        /// <returns></returns>
        public virtual string GetDbTableName() { return ""; }  
        //定义一个字典,匹配数据库中字段名
        protected Dictionary<string, string> dic = new Dictionary<string, string>()
        {
            {"卡号","CardNo" },
            {"学号","StudentNo" },
            {"学生姓名","StudentName" },           
             ……            
             ……     
            {"且","and" },            
            {"或","or" },
            {"","" }
        };
        public combineInquiry()
        {
            InitializeComponent();
            //设置dateTime控件的最大最小时间限制
            dateTimePicker1.MinDate = new DateTime(2018, 1, 1);
            dateTimePicker1.MaxDate = DateTime.Today;
            dateTimePicker2.MinDate = new DateTime(2018, 1, 1);
            dateTimePicker2.MaxDate = DateTime.Today;
            dateTimePicker3.MinDate = new DateTime(2018, 1, 1);
            dateTimePicker3.MaxDate = DateTime.Today;
        }
        private void combineInquiry_Load(object sender, EventArgs e)
        {
            //控件的初始化
            cboField2.Enabled = false;
            cboField3.Enabled = false;
            cboMark2.Enabled = false;
            cboMark3.Enabled = false;
            txtContent2.Enabled = false;
            txtContent3.Enabled = false;
            cboConbination1.Enabled = false;
            cboConbination2.Enabled = false;
            //组合关系
            cboConbination1.Items.Add("或");
            cboConbination1.Items.Add("且");
            cboConbination2.Items.Add("或");
            cboConbination2.Items.Add("且");
            //将时间控件设为不可用 不可见 
            dateTimePicker1.Enabled = false;
            dateTimePicker1.Visible = false;
            dateTimePicker2.Enabled = false;
            dateTimePicker2.Visible = false;
            dateTimePicker3.Enabled = false;
            dateTimePicker3.Visible = false;                        
        }
        //查询功能
         private void btnInquiry_Click(object sender, EventArgs e)
        {
            //判空
            foreach (Control ctl in panel1.Controls)
            {
                if ((ctl is ComboBox||ctl is TextBox)&&ctl.Enabled==true)
                {
                    if (ctl.Text.Trim()=="")
                    {
                        MessageBox.Show("请将信息填写完整!","温馨提示");
                        return;
                    }
                }
            }

            //实例化外观层 实体层
            FacadeGroupFindTemplate facadeBoolGroupFindTemplate = new FacadeGroupFindTemplate();
            GroupFindTemplate_Info groupFindTemplate = new GroupFindTemplate_Info();
            //给实体层传值
            groupFindTemplate.Dbtablename = GetDbTableName();

            groupFindTemplate.cboField1 = dic[cboField1.Text.Trim()];
            groupFindTemplate.cboField2 = dic[cboField2.Text.Trim()];
            groupFindTemplate.cboField3 = dic[cboField3.Text.Trim()];

            groupFindTemplate.cboMark1 = cboMark1.Text.Trim();
            groupFindTemplate.cboMark2 = cboMark2.Text.Trim();
            groupFindTemplate.cboMark3 = cboMark3.Text.Trim();
	        	
            if (txtContent1.Enabled==true)
            {
                groupFindTemplate.Content1 = txtContent1.Text.Trim();
                groupFindTemplate.Content2 = txtContent2.Text.Trim();
                groupFindTemplate.Content3 = txtContent3.Text.Trim();
            }
            else
            {
                groupFindTemplate.Content1 = dateTimePicker1.Text.Trim();
                groupFindTemplate.Content2 = dateTimePicker2.Text.Trim();
                groupFindTemplate.Content3 = dateTimePicker3.Text.Trim();
            }

            groupFindTemplate.Relationship1 = dic[cboConbination1.Text.Trim()];
            groupFindTemplate.Relationship2 =dic[cboConbination2.Text.Trim()];

            //判断是否查找成功
            bool result = false;
            result = facadeBoolGroupFindTemplate.boolGroupFindTemplate(groupFindTemplate);
            if (result==true)
            {                
                DataTable dt = facadeBoolGroupFindTemplate.groupFindTemplate(groupFindTemplate);
                dataGridView1.DataSource = dt;
                dataGridView1.AllowUserToAddRows = false;
                //MessageBox.Show("查找成功!", "温馨提示");//直接在datagridview显示,减少弹框,提高用户体验度
            }
            else
            {
                MessageBox.Show("不存在您查找的信息","温馨提示");
                dataGridView1.DataSource = null;
            }            
        }
        /// <summary>
        /// 清空+控件初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClear_Click(object sender, EventArgs e)
        {       
        	//清空容器panel里的所有内容               
            foreach (Control control in panel1.Controls)
            {                
                if (control is TextBox)
                {
                    control.Text = string.Empty;
                    
                }
                else if (control is ComboBox)
                {
                    ComboBox cbo = control as ComboBox;
                    cbo.SelectedIndex = -1;
                }
            }
            //清空组合关系框内容
            cboConbination1.SelectedIndex = -1;
            cboConbination2.SelectedIndex = -1;
            DataTable table = null;
            dataGridView1.DataSource = table;

            //控件的初始化
            cboField2.Enabled = false;
            cboField3.Enabled = false;
            cboMark2.Enabled = false;
            cboMark3.Enabled = false;
            txtContent2.Enabled = false;
            txtContent3.Enabled = false;
            cboConbination1.Enabled = false;
            cboConbination2.Enabled = false;            
        }
        /// <summary>
        /// 如果选择了第一个组合关系,下一行信息可选
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void cboConbination1_SelectedIndexChanged(object sender, EventArgs e)
        {
            string relationship = cboConbination1.Text.Trim();
            switch (relationship)
            {
            	//使用case事件代替ifelse语句,减少代码量
                case "且":
                    cboField2.Enabled = true;
                    cboMark2.Enabled = true;
                    txtContent2.Enabled = true;
                    break;
                case "或":
                    cboField2.Enabled = true;
                    cboMark2.Enabled = true;
                    txtContent2.Enabled = true;
                    break;
            }
            
        /// <summary>
        /// 当第一行所有的内容添加完毕,第一个关系下拉框被**
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtContent1_TextChanged(object sender, EventArgs e)
        {
            if (cboField1.Text != "" && cboMark1.Text != "" && txtContent1.Text != "")
            {
                cboConbination1.Enabled = true;
            }
        }

        /// <summary>
        /// 当第二行所有的内容添加完毕,第二个关系下拉框被**
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void txtContent2_TextChanged(object sender, EventArgs e)
        {
            if (cboField2.Text != "" && cboMark2.Text != "" && txtContent2.Text != "")
            {
                cboConbination2.Enabled = true;
            }
        }
        
        /// <summary>
        /// 构造一个没有返回值的虚方法,子窗体根据自身内容来实例化
        /// </summary>
        /// <param name="field"></param>
        /// <param name="mark"></param>
        
        public virtual void addContent(ComboBox field, ComboBox mark){ }
       /// <summary>
        /// 根据field的内容 来添加Mark中的符号  (这里只给出一个,因为后面两个和第一个一样)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void cboField1_SelectedIndexChanged(object sender, EventArgs e)
        {
            addContent(cboField1,cboMark1);
            if (cboField1.Text=="注册日期"|| cboField1.Text == "注册时间" || cboField1.Text == "登录日期" || cboField1.Text == "登录时间" || cboField1.Text == "上机日期" ||cboField1.Text == "下机日期"||cboField1.Text=="注销日期")
            {
                dateTimePicker1.Format = DateTimePickerFormat.Custom;

                dateTimePicker1.Visible = true;
                dateTimePicker1.Enabled = true;

                txtContent1.Visible = false;
                txtContent1.Enabled = false;
                dateTimePicker1.CustomFormat = "yyyy-MM-dd";                                
            }
            else
            {
                txtContent1.Visible = true;
                txtContent1.Enabled = true;

                dateTimePicker1.Visible = false;
                dateTimePicker1.Enabled = false;
                return;
            }            
        /// <summary>
        /// 导出为Excel表,调用封装好的exportExcel方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExcel_Click(object sender, EventArgs e)
        {
            string name = "Mark";
            exportExcel export = new exportExcel();
            export.RExcel(name,dataGridView1);
        }
        /// <summary>
        /// 如果是时间控件,在第一行所有内容都填满之后,第一个组合关系可使用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {            
            if (cboField1.Text != "" && cboMark1.Text != "" && dateTimePicker1.Text != "")
            {
                cboConbination1.Enabled = true;
            }
        }        
        private void dateTimePicker2_ValueChanged_1(object sender, EventArgs e)
        {
            if (cboField2.Text != "" && cboMark2.Text != "" && dateTimePicker2.Text != "")
            {
                cboConbination2.Enabled = true;
            }
     }

D层也很简答,因为我用了存储过程

 public class DALGroupFindTemplate:IDALGroupFindTemplate
    {
        SQLHelper sqlHelper = new SQLHelper();
        public DataTable GroupFindTemplate(GroupFindTemplate_Info groupfind)
        {
            SqlParameter[] sqlParams = { new SqlParameter("@cboField1", groupfind.cboField1),
                                         new SqlParameter("@cboField2", groupfind.cboField2),
                                         new SqlParameter("@cboField3", groupfind.cboField3),
                                         new SqlParameter("@cboMark1",groupfind.cboMark1),
                                         new SqlParameter("@cboMark2",groupfind.cboMark2),
                                         new SqlParameter("@cboMark3",groupfind.cboMark3),
                                         new SqlParameter("@txtContent1",groupfind.Content1),
                                         new SqlParameter("@txtContent2",groupfind.Content2),
                                         new SqlParameter("@txtContent3",groupfind.Content3),
                                         new SqlParameter("@Relationship1",groupfind.Relationship1),
                                         new SqlParameter("@Relationship2",groupfind.Relationship2),
                                         new SqlParameter("@Dbtablename",groupfind.Dbtablename)
                                       };
            string sql = "PROC_GroupCheck";
            DataTable dt = sqlHelper.ExecuteQuery(sql, sqlParams, CommandType.StoredProcedure);
            return dt;
        }

OK,父窗体搞定,下面开始解决子窗体。以学生基本信息查询为例,只需要在U层做简单改动即可。

 		/// <summary>
        /// 重写父窗体addContent方法,匹配对应的字段名和操作符
        /// </summary>
        /// <param name="field"></param>
        /// <param name="mark"></param>
        
        public override void addContent(ComboBox field, ComboBox mark)
        {
            switch (field.Text)
            {
                case "学生姓名":
                case "性别":
                case "系别":
                case "备注":
                case "状态":
                case "是否结账":
                    mark.Text = "";
                    mark.Items.Clear();
                    mark.Items.Add("=");
                    mark.Items.Add("<>");
                    break;
                case "卡号":
                case "学号":
                case "余额":
                case "操作员ID":
                case "年级":
                case "班级":
                case "注册日期":
                    mark.Text = "";
                    mark.Items.Clear();
                    mark.Items.Add("=");
                    mark.Items.Add("<>");
                    mark.Items.Add(">");
                    mark.Items.Add("<");
                    break;
            }
        }
        
        /// <summary>
        /// 返回要查询的表名
        /// </summary>
        /// <returns></returns>
        
        public override string GetDbTableName()
        {
            return "Student_Info";
        }
        
        /// <summary>
        /// 在datagridview表中加入对应的标头
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void btnInquiry_Click(object sender, EventArgs e)
        {
            if (dataGridView1.Rows.Count>0)
            {
                dataGridView1.Columns[0].HeaderText = "卡号";
                dataGridView1.Columns[1].HeaderText = "学号";
                dataGridView1.Columns[2].HeaderText = "学生姓名";
                dataGridView1.Columns[3].HeaderText = "性别";
                dataGridView1.Columns[4].HeaderText = "系别";
                dataGridView1.Columns[5].HeaderText = "年级";
                dataGridView1.Columns[6].HeaderText = "班级";
                dataGridView1.Columns[7].HeaderText = "余额";
                dataGridView1.Columns[8].HeaderText = "备注";
                dataGridView1.Columns[9].HeaderText = "操作员ID";
                dataGridView1.Columns[10].HeaderText = "是否结账";
                dataGridView1.Columns[11].HeaderText = "注册日期";
                dataGridView1.Columns[12].HeaderText = "注册时间";
                dataGridView1.Columns[13].HeaderText = "状态";
            }
        }
        
        /// <summary>
        /// 添加字段
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void frmOpStuMaintenance_Load(object sender, EventArgs e)
        {
            //定义一个数组,然后每个combo加载,简单粗暴
            string[] Field = { "卡号","学号","学生姓名","性别","系别","年级", "班级", "余额", "备注", "操作员ID", "是否结账","注册日期", "状态" };
            cboField1.Items.AddRange(Field);
            cboField2.Items.AddRange(Field);
            cboField3.Items.AddRange(Field);
        }
        
    }

模板方法到这里就已经结束了,用了模板方法之后是不是有一种一劳永逸的感觉?哈哈。