我一直探讨怎样把代码写的更简洁,尤其大型的系统如果架构设计得好得话,可以省去多少代码和时间啊,同时也能跟便于后人维护。想必大家都看过或学过微软Pet Shop的例子,说真的我很佩服它里面所用到的技术,但却不敢苟同它的设计,想必看过的人都知道要想把它看懂是不是还真的花点时间,而对应这个例子,它的业务逻辑其实不很复杂。如果那个大型系统,一个数据插入就关系到好几个业务。如果都象那样设计,那样得花多少时间啊。想必没有那儿实际开发得完全参考。(如大家有什么不同观点,欢迎讨论)
所以我一直寻找一个好的设计思想。希望大家可以探讨一下。
下面是从我的一个实际项目的架构设计,分解的一个Demo(添加员工信息)。采用的三层结构:应用层,业务逻辑层,数据层,和分布式系统设计技术(Remoting),Com+事务。(设计很简单,明了很容易就能看懂,也很容易写代码)
从数据层开始:
建立一个类DataBase作为数据层底层,用于连接数据库,这样保存一个客户端只有一个数据库连接,其他数据操作层从类派生。
namespace DAL
{
public class DataBase
{
protected SqlConnection conn;
private static string connStr = ConfigurationManager.ConnectionStrings["SqlConnectionString"].ConnectionString;
public DataBase()
{
conn = new SqlConnection(connStr);
}
public bool MyConnect()
{
try
{
if (conn.State == ConnectionState.Closed )
{
conn.Open();
}
return true;
}
catch (SqlException ex)
{
throw ex;
}
}
}
}
namespace DAL
{
public class DalWorkerInfo:DataBase
{
/**//// <summary>
/// 增加员工
/// </summary>
/// <param name="WorkerID">工号</param>
/// <param name="Name">姓名</param>
/// <param name="Age">年龄</param>
/// <param name="Tel">电话</param>
/// <returns>成功,返回true</returns>
public bool AddWorkerInfo(string WorkerID,string Name,Int32 Age,string Tel)
{
SqlCommand cmd;
string strSQL;
try
{
if (MyConnect() == false)
{
return false;
}
strSQL = "insert into WorkerInfo(WorkerID,Name,Age,Tel) values ('" + WorkerID + "','" + Name + "','" + Age + "','" + Tel + "')";
cmd = new SqlCommand(strSQL);
cmd.Connection = conn;
cmd.ExecuteNonQuery();
return true;
}
catch (SqlException ex)
{
throw ex;
}
finally
{
conn.Close();
}
}
/**//// <summary>
/// 获得所有员工信息
/// </summary>
/// <returns></returns>
public DataTable GetWorkerInfo()
{
SqlDataAdapter da;
DataTable dt=new DataTable ();
string strSQL;
try
{
if (MyConnect() == false)
{
return null;
}
strSQL = "select * from WorkerInfo";
da = new SqlDataAdapter(strSQL, conn);
da.Fill(dt);
return dt;
}
catch (SqlException ex)
{
throw ex;
}
finally
{
conn.Close();
}
}
/**//// <summary>
/// 按工号,查询员工信息
/// </summary>
/// <param name="WorkID"></param>
/// <returns></returns>
public DataTable GetWorkerInfo(string WorkID)
{
SqlDataAdapter da;
DataTable dt = new DataTable();
string strSQL;
try
{
if (MyConnect() == false)
{
return null;
}
strSQL = "select * from WorkerInfo where WorkerID='" + WorkID + "'";
da = new SqlDataAdapter(strSQL, conn);
da.Fill(dt);
return dt;
}
catch (SqlException ex)
{
throw ex;
}
finally
{
conn.Close();
}
}
}
}
数据层就这么简单,如果还有很多的业务逻辑可以单独再新建一个类也是从DataBase派生。
业务逻辑层:
业务逻辑层调用数据的进行业务,每个业务里面可能要调用很多个数据层的方法,这就看你个系统大小了。我的这个demo中增加员工信息这个业务时,只有两个步骤:一是插入员工信息,如果不成功,回滚事务,如果成功,接着进行该业务, 向系统日志中写如日志(这是一般系统对数据更新都要进行的一步:写入日志)。写入日志也完成,这个添加员工信息的这个业务就算完成了,然后提交事务,返回值。如果你的一个业务逻辑很多的话,那就可以调用多个数据层方法,同时使用事务,保证一个业务的所有步骤都正确完成。
namespace BLL
{
public class BllWorkerInfo:MarshalByRefObject
{
/**//// <summary>
/// 增加员工
/// </summary>
/// <param name="WorkerID">工号</param>
/// <param name="Name">姓名</param>
/// <param name="Age">年龄</param>
/// <param name="Tel">电话</param>
/// <returns>成功,返回true</returns>
public bool AddWorkerInfo(string WorkerID, string Name, int Age, string Tel)
{
DAL.DalWorkerInfo dal = new DAL.DalWorkerInfo();
ServiceConfig sc = new ServiceConfig();
//在业务层中,处理事务(COM+事务)
sc.Transaction = TransactionOption.Required;
sc.TrackingEnabled = true;
ServiceDomain.Enter(sc);
try
{
//1-业务处理1
if (dal.AddWorkerInfo(WorkerID, Name, Age, Tel) == false)
{
ContextUtil.SetAbort();//回滚事务
return false;
}
//2-业务处理2:写入系统日志
//此处 省略..
//.
//3-业务处理3:.
//
//..
//所有业务正确处理完成,提交事务,返回ture
ContextUtil.SetComplete();
return true;
}
catch
{
ContextUtil.SetAbort();//回滚事务
throw;
}
finally
{
// sc = null;
dal = null;
ServiceDomain.Leave();
}
}
public DataTable GetWorkerInfo()
{
DAL.DalWorkerInfo dal = new DAL.DalWorkerInfo();
try
{
return dal.GetWorkerInfo();
}
catch
{
return null;
}
}
}
}
而应用层只需要调用业务层的方法,然后就不用去管了,所有的业务逻辑都交给业务层去处理
{
BLL.BllWorkerInfo bll = new BLL.BllWorkerInfo();
try
{
if (bll.AddWorkerInfo(txtWorkerID.Text.Trim (), txtName.Text, int.Parse (txtAge.Text) ,txtTel.Text.Trim ()))
{
UpdateData();
MessageBox.Show("增加成功");
}
else
{
MessageBox.Show("增加失败");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
}
}
void UpdateData()
{
BLL.BllWorkerInfo bll = new BLL.BllWorkerInfo();
try
{
this.dataGridView1.DataSource = bll.GetWorkerInfo();
}
catch
{
}
}
}
看完上面的介绍是不是觉得一个三层架构的设计其实很简单,想必这样的代码不用看多久就能够马上看懂。同时采用了分层,以后维护也更加方便。就算业务改变了,也只需改变业务层的代码。
如果你是一个大型系统,将之变为一个分布式的系统也简单,改业务层的类从MarshalByRefObject派生,在服务器端,注册业务层类为远程对象,在客户端直接调用远程对象。
这个可以在Vs 2005中使用配置文件完成,稍加点代码就可以完成一个分布系统的发布。
可以写个Window服务程序,用来注册远程对象
只要加入:RemotingConfiguration.Configure("RemoteServer.exe.config", false);
< configuration >
< connectionStrings >
< add name ="ArchDesign.Properties.Settings.DataBaseConnectionString"
connectionString ="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
providerName ="System.Data.SqlClient" />
< add name ="SqlConnectionString"
connectionString ="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
< system .runtime.remoting >
< application name ="RemoteHostService" >
< service >
< wellknown type ="BLL.BllWorkerInfo,BllWorkerInfo" objectUri ="BllWorkerInfo" mode ="SingleCall" />
</ service >
< channels >
<!-- <channel type="System.Runtime.Remoting.Channels.Tcp,System.Runtime.Remoting" port="9999" /> -->
< channel ref ="tcp" port ="9999" />
<!-- <channel ref="http" port="8888" />
<channel ref="ipc" portName="testPipe" /> -->
</ channels >
</ application >
</ system.runtime.remoting >
</ configuration >
客户端可以直接用New调用远程对象,在程序开始是运行配置文件:RemotingConfiguration.Configure("RemoteServer.exe.config", false);
< configuration >
< configSections >
</ configSections >
< connectionStrings >
< add name ="ArchDesign.Properties.Settings.DataBaseConnectionString"
connectionString ="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
providerName ="System.Data.SqlClient" />
< add name ="SqlConnectionString"
connectionString ="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
< system .runtime.remoting >
< application name ="RemoteHostClient" >
< client >
< wellknown type ="BLL.BllWorkerInfo,BllWorkerInfo" url ="tcp://localhost:9999/BllWorkerInfo" />
</ client >
< channels >
</ channels >
</ application >
</ system.runtime.remoting >
</ configuration >
一个简单的三层结构的架构就达起来了,可能其中还有某些不足的地方,例如由于保存一个客户端只要一个数据连接,都从一个数据低层派生,如果是多个数据库那就有问题。还有就是如果一个业务参数过多,每个参数写起来也很麻烦,修改起来还得看下参数的顺序,可以把他改为类对象,每个数据表对应一个类,类似
pet Shop的设计,同时可以将业务层写个接口,只提供接口给客户端调用,这个可以同时开发。总之我觉得整个设计一个就是简单,像事务处理,业务逻辑这样一写都非常明了,以后维护起来也很方便。如果大家觉得有更好的简洁的设计欢迎大家指点宝贵的意见,相互学习。
/Files/zhang3533/ArchDesign.rar