三层的两次重构

三层总结


1.第一次架构

1.基本三层
2.分页
3.主键外键

1.基本三层

0.1 model层 主要模拟数据库中的表,以c#的方式对数据进行处理

1.针对sql数据库进行连接操作的DAL 并且DAL中没个表都要用DAO做后缀名
当数据库的表是复数形式时,DAO中的后缀改成单数形式

2.业务逻辑层 BLL 主要是进行行业务逻辑判断 并不是对数据进行直接处理

3.UI层 直接面对用户 对用户显示功能的用处

// 三层之中的引用关系

1.DAL

2.三层的处理

A/ 非查询和查询

1.非查询

增删改(增)

UI 1.引用BLL层
2.创建一个学生对象 收学生对象的所有信息
3.创建一个bool的实体,将这个实体传递给bll层中
4.根据bll层的判断,根据判断得出结果


BLL 1.引用到dal层
2.接收到ui层传来的实体并且将值传递给dal层
3.判断DAL层传来的值进行判断是否大于0


DAL 1.接收到bll层中的实体
2.执行sql的命令 并用字符注入的方式
3.创建一个集合
4.并且将传过来的实体注入到这个集合中
5.封装sqlhello类
6.将所有要实现的方法写在里面
7.将参数传递给sqlhello类中执行并且返回需要实现的方法类型值
8.返回一个ExecuteNonQuery并且返回到bll层
UI

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using BLL;
using Model;

namespace UI
{
public partial class xz : Form
{


public xz()
{
InitializeComponent();


}

private void button1_Click(object sender, EventArgs e)
{

studentseres dao = new studentseres();
students s = new students();
s.son = textBox1.Text;
s.name = textBox2.Text;
s.sex = textBox3.Text;
s.age = Convert.ToInt32(textBox4.Text);
bool fiel = dao.zzj(s);
if (fiel)
{

MessageBox.Show("成功");


}
else
{

MessageBox.Show("失败");

}

}
}
}

//增加学生
public bool zzj(students s)
{


return dao.zj(s) > 0;


}

//增
public int zj(students s)
{


string sql = "insert into students values(@sno,@name,@sex,@age)";
List<SqlParameter> pra = new List<SqlParameter>();
pra.Add(new SqlParameter("@sno", s.son));
pra.Add(new SqlParameter("@name", s.son));
pra.Add(new SqlParameter("@sex", s.son));
pra.Add(new SqlParameter("@age", s.son));
return sqlhello.ExecuteNonQuery(sql, pra);


}

//sqlhello方法


public class sqlhello
{


public static DataTable baba(string sql,List<SqlParameter>pra)
{


SqlConnection conn = new SqlConnection("server=.;database=SchoolIDB;uid=sa;pwd=123");
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
if (pra != null)
{

cmd.Parameters.AddRange(pra.ToArray()); //查

}
DataSet set = new DataSet();
SqlDataAdapter hh = new SqlDataAdapter(cmd);
hh.Fill(set);
return set.Tables[0];

}
public static int ExecuteNonQuery(string sql, List<SqlParameter> pra)
{
SqlConnection conn = new SqlConnection("server=.;database=SchoolIDB;uid=sa;pwd=123");
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
if (pra != null)
{

cmd.Parameters.AddRange(pra.ToArray()); //非查

}
return cmd.ExecuteNonQuery();





}

}

}


2.非查询

1.删、改

UI 1.首先必须强制用户选择一行
2.收集id信息 将id传递给bll层
3.和增加相同

private void button3_Click(object sender, EventArgs e)
{


if (benben.SelectedRows.Count == 0)
{

MessageBox.Show("请先选择一行");


}
else
{

int id = Convert.ToInt32(benben.SelectedRows[0].Cells["id"].Value);
bool r = dao.ssc(id);
if (r)
{

MessageBox.Show("删除成功");

}
else
{

MessageBox.Show("删除失败");
}


}

BLL

public bool ssc(int id)
{

return dao.sc(id) > 0;



}

DAL
public int sc(int id)
{

string sql = "delete from students where id=@id ";
List<SqlParameter> pra = new List<SqlParameter>();
pra.Add(new SqlParameter("@id", id));
return sqlhello.ExecuteNonQuery(sql, pra);


}


//查询 查询单个值和一批值都可以用datable

1.创建一个bll层的对象
2.创建一个用户对象收集用户登录信息
3.并且将这个值传递给bll
3.通过bll返回的值得到结果


//ui 层
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using model;
using BLL;

namespace ui
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
userserver u = new userserver();
private void button1_Click(object sender, EventArgs e)
{

user user = new user();
user.username = textBox1.Text.Trim();
user.password = textBox2.Text.Trim();
if (u.checkuser(user))
{

MessageBox.Show("登录成功");

}
else
{

MessageBox.Show("登录失败");
}
}
}
}

//bll层
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using model;
using DAL;

namespace BLL
{
public class userserver
{

userDAO dao = new userDAO();
public bool checkuser(user user)
{

user u = dao.getubysername(user.username);
if (u == null)
{

return false;

}
else
{

return u.password == user.password;


}


}

}
}


dal层

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using model;
using System.Data;
using System.Data.SqlClient;

namespace DAL
{
public class userDAO
{
public user getubysername(string username)
{


string sql = "select * from users where username=@username";
List<SqlParameter> pra = new List<SqlParameter>();
pra.Add(new SqlParameter("username", username));
DataTable dt = SqlHelperDAO.getnemane(sql, pra);
user user = null;
if (dt.Rows.Count == 1)
{

user = new user();
DataRow row =dt.Rows[0];

user.userid = Convert.ToInt32(row[0]);
user.username = row[1].ToString();
user.password = row[2].ToString();


}
return user;

}


}

}

2.查询一批值

1.从bll中传递过来的值通过集合存储起来
2.并且通过当前集合将这个绑定
3.bll层将数据传递给ui层
4.dal层查询所有学生信息并且返回一批学生信息
private studentsserver ss=new studentsserver
list<student>students=ss.dao()l
dgvstudents.datasource=students


2.BLL
private studensdao dao=new studensdao();
public List<students> gg()
{

return dao.name();


}

3.DAL


//查询所有学生对象
public List<students> name()
{


string sql = "select * from students";
DataTable u = sqlhello.baba(sql, null);
List<students> students = new List<students>();
for (int i = 0; i < u.Rows.Count; i++)
{

students ss = new students();
ss.id = Convert.ToInt32(u.Rows[0]["id"]);
ss.son = u.Rows[1]["son"].ToString();
ss.name = u.Rows[2]["name"].ToString();

students.Add(ss);


} return students;

2.分页查询

ui 1.初始显示所设置
a.页码 2.一页显示中的数目 3.所有的数目
private int pageIndex = 1;
private int pageSize = 10;
private int count;
2.将三个参数传递给bll层
List<Student> students =ss.GetStudentListByPage(pageIndex, pageSize,ref count);
dgvStudents.DataSource = new BindingList<Student>(students);
3.通过事件(按钮)来进行分页
this.pageIndex++;
if (pageIndex == (count % pageSize == 0 ? count / pageSize : count / pageSize + 1))
{
btnNext.Enabled = false;
}
btnPrev.Enabled = true;
this.ShowStudent();
}

//if(pageIndex==1)
{

btnNext.Enabled = false;
}
this.showstudent()

bll层 1.接收到ui层的参数,并且将参数传递给DAL层
//public List<Student> GetStudentListByPage(int pageIndex, int pageSize,ref int count)//传递参数
//{
// return dao.GetStudentListByPage(pageIndex, pageSize,ref count);//传递给dal层
//}

DAL层 从bll层接收到三个参数
sql:建立一个以id从大到小的表并且以这个为条件
页码条件:页码*页数-(页数-1)
页数条件:页码*页数
建立参数集合与sql命令传递给sqlhello中执行
将sqlhello传递过来的表接住
建立一个集合循环讲话值加到里面去
2.再查询一个coun的命令并且放在sqlhello执行
并且加入到每个学生的中
// string sql = "select * from (select ROW_NUMBER() over(order by Id) as sid,* from Students ) temp where sid>=@pageIndex*@pageSize-(@pageSize-1) and sid<=@pageIndex*@pageSize";
// List<SqlParameter> paras = new List<SqlParameter>();
// paras.Add(new SqlParameter("@pageIndex", pageIndex));
// paras.Add(new SqlParameter("@pageSize", pageSize));
// DataTable dt= SqlHelper.ExecuteTable(sql, paras);
// List<Student> students = new List<Student>();
// for (int i = 0; i < dt.Rows.Count; i++)
// {
// Student s = new Student();
// s.Id = Convert.ToInt32(dt.Rows[i]["Id"]);
// s.Name = dt.Rows[i]["Name"].ToString();
// s.Sno = dt.Rows[i]["Sno"].ToString();
// s.Sex = dt.Rows[i]["Sex"].ToString();
// s.Age = Convert.ToInt32(dt.Rows[i]["Age"]);
// s.GradeId = Convert.ToInt32(dt.Rows[i]["GradeId"]);
// students.Add(s);
// }
// sql = "select COUNT(*) from Students";//所有的总和
// count=Convert.ToInt32( SqlHelper.ExecuteScalar(sql, null));//查询所有学生数
// return students;
//}

2.分页第二种方法:
在ui层设置页码、页数之后传递给bll层,bll层接受到页码与页数后执行命令传递会ui
按钮(事件) 页码+-1并且执行showstudents 达到分页的效果

3.外键主键

基本过程

将年级对象写到学生对象中,创建学生对象并且用学生对象查找学生的年级id,调用返回的学生对象集合,创建年级对象集合并且调用年级集合的方法,并且将
通过判断查出来年级id得值覆盖到年级id之中,并且在ui层显示所有学生信息与年级信息
//注意
主外键的单向性

1.一个年级队形可以保存多个学生对象
2.在年级对象类中根据年级编号来查询年级对象
3.在创建学生编号的时候new一个年级对象并且调用年级对象的id将学生对象id传递
3.可以写null (参数)


例:


namespace Model //model层 写入年级
{
public class Student
{
public int Id { get; set; }
public string Sno { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public int Age { get; set; }
public int GradeId { get; set; }
//导航属性
public Grade Grade { get; set; }


}
}

DAL 层

public List<Student> GetStudentList()
{
string sql = "select * from students";
DataTable dt= SqlHelper.ExecuteTable(sql, null);
List<Student> students = new List<Student>();
for (int i = 0; i < dt.Rows.Count; i++) //查找学生的年级
{
Student s = new Student();
s.Id =Convert.ToInt32( dt.Rows[i]["Id"]);
s.Sno = dt.Rows[i]["Sno"].ToString();
s.Name = dt.Rows[i]["Name"].ToString();
s.Sex = dt.Rows[i]["Sex"].ToString();
s.Age = Convert.ToInt32(dt.Rows[i]["Age"]);
s.GradeId = Convert.ToInt32(dt.Rows[i]["GradeId"]);

students.Add(s);
}
return students;
}

public List<Grade> GetGradeList()
{
string sql = "select * from grades";
DataTable dt= SqlHelper.ExecuteTable(sql, null); //所有年级
List<Grade> grades = new List<Grade>();
for (int i = 0; i < dt.Rows.Count; i++)
{
Grade g = new Grade();
g.GradeId = Convert.ToInt32(dt.Rows[i]["GradeId"]);
g.GradeName = dt.Rows[i]["GradeName"].ToString();
grades.Add(g);
}
return grades;
}
}
}


BLL层

public class StudentService
{
private IStudentDAO dao = AbstractFactory.CreatDAO<IStudentDAO>() ;
//获取所有学生信息
public List<Student> GetStudentList()
{
List<Student> students= dao.GetStudentList();
List<Grade> grades = new GradeDAO().GetGradeList();//创建对象并且调用方法
for (int i = 0; i < students.Count; i++)
{
for (int j = 0; j < grades.Count; j++) //循环判断
{
if (students[i].GradeId == grades[j].GradeId)
{
students[i].Grade = grades[j];
break;
}
}
}
return students;
}

UI层


private StudentService ss = new StudentService();
private void FrmStudent_Load(object sender, EventArgs e)
{
this.btnPrev.Enabled = false;
this.ShowStudent();
}



第二次重构三层


1.简单工厂模式
2.抽象工厂模式
3.反射
4,委托


1.简单工厂模式

简单工厂设计模式

1.首先创建一个人的旅游的方法
private Interface1 jiaoton = gongchang.jiaotong(); //人从工厂得到一个对象法
public void ff()
{

Console.WriteLine("我在旅游");
jiaoton.row();

}


2.创建一个跑的接口 (共同的行为)
public interface Interface1
{
void row();

}

3.创建一个具体的跑的对象(车)并且继承跑的接口
public class CHE:Interface1
{

public void row()
{
Console.WriteLine("在开车");
}
}
}

4.创建一个接口工厂 将生成的对象传递给具体的需要的人
public static Interface1 jiaotong()

{
string jt = ConfigurationManager.AppSettings["st"];
Interface1 jiaotong = null;
switch (jt)


{
case "CHE": jiaotong = new CHE(); break;

} return jiaotong;


}
}

5.app.config 部分 //注意调用addconfi命令时 需要引用configuration
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>//读取


<add key="st" value="CHE"/>//通过key值来判断工厂生产的交通工具 //可以通过key获取value,一般用这种方法配置全局内使用的字符串。


</appSettings>
</configuration>


6.创建一个对象并且调用了方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
ren R = new ren();
R.ff();

}
}
}


2.抽象工厂模式


过程:

比方说对象是人
人通过总工厂来选择系列工厂
比方说系列工厂有两个 一个是高级工厂 一个是低级工厂

一个交通工具和武器的接口来定义规范
比方说交通工具有车子和飞机
武器有ak和火箭


在总工厂选择了具体的工厂后
例如 选择了高级工厂,那
么通过定义可以实现飞机和火箭的实现
与此类推就是抽象工厂模式


例子讲解

具体实现:

//先选择到工厂 并且在工厂中拿到跑和射击的行为
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class Person
{
private AbstractFactory factory = AbstractFactory.ChooseFactory();
public void Travel()
{
IRunable vehicle = factory.CreatVehicle();
IShotable weapon = factory.CreatWeapon();
Console.WriteLine("人在旅行....");
vehicle.Run();
weapon.Shot();
}
}
}


总工厂选择


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Reflection;
namespace ConsoleApplication2
{
public abstract class AbstractFactory
{
public abstract IRunable CreatVehicle();
public abstract IShotable CreatWeapon();
public static AbstractFactory ChooseFactory()
{
string factoryName = ConfigurationManager.AppSettings["FactoryName"]; //加载配文件置并且基于反射技术找到
//基于反射技术根据类名动态创建该类的对象
return Assembly.GetExecutingAssembly().CreateInstance("ConsoleApplication2." + factoryName) as AbstractFactory; //实现

}
}
}


app 配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="FactoryName" value="GDSFactory"/> //选择具体工厂
</appSettings>
</configuration>


具体工厂()
// 低级工厂 选择具体的接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace ConsoleApplication2
{
public class GDSFactory : AbstractFactory
{
public override IRunable CreatVehicle()
{
return new Plane();
}
public override IShotable CreatWeapon()
{
return new Boom();
}
}
}

高级工厂 选择具体的接口


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class DXXFactory : AbstractFactory
{
public override IRunable CreatVehicle()
{
return new Car();
}
public override IShotable CreatWeapon()
{
return new AK47();
}
}
}


具体的行为


using System;
using System.Collections.Generic;
using System.Linq; //汽车
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public interface IRunable
{
void Run();
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//射击
namespace ConsoleApplication2
{
public interface IShotable
{
void Shot();
}
}


//具体实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class Boom : IShotable
{ //炸弹

public void Shot()
{
Console.WriteLine("扔着炸弹轰炸.....");
}
}
}

//具体实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2 //飞机 高大上
{
public class Plane : IRunable
{
public void Run()
{
Console.WriteLine("飞机在天上飞.....");
}
}
}

//具体实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class Car : IRunable //低级
{
public void Run()
{
Console.WriteLine("轿车在飞快的跑.....");
}
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class AK47 : IShotable //低级
{
public void Shot()
{
Console.WriteLine("拿着AK47在射击....");
}
}
}

2.委托

1.委托

简而言之委托就是讲方法当做参数使用,一个保存方法的类型,委托是一个类,它定义了方法的类型
、使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,
同时使得程序具有更好的可扩展性。

基本语法

public delegate void dele();
dele dele=方法(); //注意:如果通过一个委托调用两个方法,会发生方法覆盖。
dele dele=方法(); //注意:如果通过一个委托调用两个方法,会发生方法覆盖。

如果要调用两个方法:
dele dele=test2;
dele+=test; //这个委托上有两个方法 依次执行
dele();


1.匿名函数

//例1
button1.Click += delegate(System.Object o, System.EventArgs e)
{ System.Windows.Forms.MessageBox.Show("Click!"); };

例2

2.匿名函数直接在调用者中调用函数
list<studen>resylt=循环方法(学生对象集合,委托方法函数(studen s){return s.sex="男"}) 1.前者
对象 2.后者是根据对象发生事件

3.lanbaba表达式

3.lambabab 表达式
1. s=>return s.age>=20; //类型对象 => 条件


4.委托中的四种方法


Where ToList FirstOrDefault OrderByDescending(最后一个)


List<Student> result = students.where(s => s.Id).ToList().[0];//根据id查到下表 表达式
List<Student> result = students.tolist(s => s.Id).ToList();//对应集合
List<Student> result = students.FirstOrDefault (s => s.Id).ToList();//拿到第一个 默认


4.反射


反射的定义:

反射是通过加载程序集来动态创建具体的实例的过程

从bll层传递给了工厂层一个学生接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model.Models;
using IDAL;
using Factory;

namespace BLL
{
public class StudentService
{
private IStudentDAO dao = SessionFactory.CreatDAO<IStudentDAO>();
public List<Student> GetStudentList()
{
return dao.GetList(s => true);
}
}
}

通过这个学生接口加载配置文件
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model.Models;
using IDAL;
using System.Reflection;
using System.Configuration;

namespace Factory
{
public class SessionFactory
{
public static T CreatDAO<T>() where T : class
{
string DllName = ConfigurationManager.AppSettings["DllName"];

配置文件的内容
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="DllName" value="DAL"/>//配置文件的内容
</appSettings>
<connectionStrings>
<add name="SchoolDbContext" connectionString="server=.;database=schooldb;uid=sa;pwd=123" providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>


并且执行配置文件的内容
Assembly assembly = Assembly.Load(DllName);
加载所查找的程序集的所有的类以循环的方式进行,并且在其中找到当前的类
Type[] types = assembly.GetTypes();
Type target = null;
for (int i = 0; i < types.Length; i++)
{
if (typeof(T).IsAssignableFrom(types[i]))
{
target = types[i];
break;
}
}

通过穿过来的参数来创建具体的类的实例
return (T)Activator.CreateInstance(target);

1.单例模式

单例模式的特点:
a:一个单例只有一个实例
b:单例必须自己创建一个唯一的实例
c:单例必须给其他对象提供这个实例

单例的应用
a:每台计算机都有若干个打印机,但只能有一个pr 避免两个打印作业同时输出打印机
b:一个具有主动编号的表可以多个用户使用,一个数据库中只有一个地方分配下一个主键编号,否则会出现主键重复

public class Singleton
{
private static Singleton _instance = null;
private Singleton(){}
public static Singleton CreateInstance()
{
if(_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}

原文地址:https://www.cnblogs.com/liyiyong/p/5227027.html