从软件结构设计,讨论代码的简洁

我一直探讨怎样把代码写的更简洁,尤其大型的系统如果架构设计得好得话,可以省去多少代码和时间啊,同时也能跟便于后人维护。想必大家都看过或学过微软Pet Shop的例子,说真的我很佩服它里面所用到的技术,但却不敢苟同它的设计,想必看过的人都知道要想把它看懂是不是还真的花点时间,而对应这个例子,它的业务逻辑其实不很复杂。如果那个大型系统,一个数据插入就关系到好几个业务。如果都象那样设计,那样得花多少时间啊。想必没有那儿实际开发得完全参考。(如大家有什么不同观点,欢迎讨论)
所以我一直寻找一个好的设计思想。希望大家可以探讨一下。
下面是从我的一个实际项目的架构设计,分解的一个Demo(添加员工信息)。采用的三层结构:应用层,业务逻辑层,数据层,和分布式系统设计技术(Remoting),Com+事务。(设计很简单,明了很容易就能看懂,也很容易写代码)
数据层开始:
建立一个类DataBase作为数据层底层,用于连接数据库,这样保存一个客户端只有一个数据库连接,其他数据操作层从类派生。

ContractedBlock.gif ExpandedBlockStart.gif 数据层DataBase
None.gifnamespace DAL
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  
public  class DataBase
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    
protected  SqlConnection conn;
InBlock.gif    
private static  string connStr = ConfigurationManager.ConnectionStrings["SqlConnectionString"].ConnectionString;
InBlock.gif    
public  DataBase()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      conn 
= new SqlConnection(connStr);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public bool MyConnect()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
if (conn.State == ConnectionState.Closed )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          conn.Open();
ExpandedSubBlockEnd.gif        }

InBlock.gif        
return true;
ExpandedSubBlockEnd.gif     }

InBlock.gif      
catch (SqlException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
throw ex;
ExpandedSubBlockEnd.gif      }

ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }

InBlock.gif
ExpandedBlockEnd.gif}
ContractedBlock.gif ExpandedBlockStart.gif 数据层,实际的对数据库的操作
None.gifnamespace DAL
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  
public class DalWorkerInfo:DataBase
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// 增加员工
InBlock.gif    
/// </summary>
InBlock.gif    
/// <param name="WorkerID">工号</param>
InBlock.gif    
/// <param name="Name">姓名</param>
InBlock.gif    
/// <param name="Age">年龄</param>
InBlock.gif    
/// <param name="Tel">电话</param>
ExpandedSubBlockEnd.gif    
/// <returns>成功,返回true</returns>

InBlock.gif    public bool AddWorkerInfo(string WorkerID,string Name,Int32 Age,string Tel)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      SqlCommand cmd;
InBlock.gif      
string strSQL;
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
if (MyConnect() == false)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          
return false;
ExpandedSubBlockEnd.gif        }

InBlock.gif        strSQL 
= "insert into WorkerInfo(WorkerID,Name,Age,Tel) values ('" + WorkerID + "','" + Name + "','" + Age + "','" + Tel + "')";
InBlock.gif        cmd 
= new SqlCommand(strSQL);
InBlock.gif        cmd.Connection 
= conn;
InBlock.gif        cmd.ExecuteNonQuery();
InBlock.gif        
return true;
ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch (SqlException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
throw ex;
ExpandedSubBlockEnd.gif      }

InBlock.gif      
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        conn.Close();
ExpandedSubBlockEnd.gif      }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// 获得所有员工信息
InBlock.gif    
/// </summary>
ExpandedSubBlockEnd.gif    
/// <returns></returns>

InBlock.gif    public DataTable GetWorkerInfo()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      SqlDataAdapter da;
InBlock.gif      DataTable dt
=new DataTable ();
InBlock.gif      
string strSQL;
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
if (MyConnect() == false)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          
return null;
ExpandedSubBlockEnd.gif        }

InBlock.gif        strSQL 
= "select * from WorkerInfo";
InBlock.gif        da 
= new SqlDataAdapter(strSQL, conn);
InBlock.gif        da.Fill(dt);
InBlock.gif        
return dt;
InBlock.gif
ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch (SqlException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
throw ex;
ExpandedSubBlockEnd.gif      }

InBlock.gif      
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        conn.Close();
ExpandedSubBlockEnd.gif      }

ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// 按工号,查询员工信息
InBlock.gif    
/// </summary>
InBlock.gif    
/// <param name="WorkID"></param>
ExpandedSubBlockEnd.gif    
/// <returns></returns>

InBlock.gif    public DataTable GetWorkerInfo(string WorkID)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      SqlDataAdapter da;
InBlock.gif      DataTable dt 
= new DataTable();
InBlock.gif      
string strSQL;
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
if (MyConnect() == false)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          
return null;
ExpandedSubBlockEnd.gif        }

InBlock.gif        strSQL 
= "select * from WorkerInfo where WorkerID='" + WorkID + "'";
InBlock.gif        da 
= new SqlDataAdapter(strSQL, conn);
InBlock.gif        da.Fill(dt);
InBlock.gif        
return dt;
InBlock.gif
ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch (SqlException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
throw ex;
ExpandedSubBlockEnd.gif      }

InBlock.gif      
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        conn.Close();
ExpandedSubBlockEnd.gif      }

ExpandedSubBlockEnd.gif    }

InBlock.gif
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif

数据层就这么简单,如果还有很多的业务逻辑可以单独再新建一个类也是从DataBase派生。
业务逻辑层:
业务逻辑层调用数据的进行业务,每个业务里面可能要调用很多个数据层的方法,这就看你个系统大小了。我的这个demo中增加员工信息这个业务时,只有两个步骤:一是插入员工信息,如果不成功,回滚事务,如果成功,接着进行该业务, 向系统日志中写如日志(这是一般系统对数据更新都要进行的一步:写入日志)。写入日志也完成,这个添加员工信息的这个业务就算完成了,然后提交事务,返回值。如果你的一个业务逻辑很多的话,那就可以调用多个数据层方法,同时使用事务,保证一个业务的所有步骤都正确完成。

ContractedBlock.gif ExpandedBlockStart.gif 业务逻辑层
None.gifnamespace BLL
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  
public class BllWorkerInfo:MarshalByRefObject 
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// 增加员工
InBlock.gif    
/// </summary>
InBlock.gif    
/// <param name="WorkerID">工号</param>
InBlock.gif    
/// <param name="Name">姓名</param>
InBlock.gif    
/// <param name="Age">年龄</param>
InBlock.gif    
/// <param name="Tel">电话</param>
ExpandedSubBlockEnd.gif    
/// <returns>成功,返回true</returns>

InBlock.gif    public bool AddWorkerInfo(string WorkerID, string Name, int Age, string Tel)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      DAL.DalWorkerInfo dal 
= new DAL.DalWorkerInfo();
InBlock.gif      ServiceConfig sc 
= new ServiceConfig();
InBlock.gif      
InBlock.gif      
//在业务层中,处理事务(COM+事务)
InBlock.gif
      sc.Transaction = TransactionOption.Required;
InBlock.gif      sc.TrackingEnabled 
= true;
InBlock.gif      ServiceDomain.Enter(sc);
InBlock.gif
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
//1-业务处理1
InBlock.gif
        if (dal.AddWorkerInfo(WorkerID, Name, Age, Tel) == false)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          ContextUtil.SetAbort();
//回滚事务
InBlock.gif
          return false;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
//2-业务处理2:写入系统日志
InBlock.gif        
//此处 省略dot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gif..
InBlock.gif        
//dot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gif.
InBlock.gif
InBlock.gif
InBlock.gif        
//3-业务处理3:dot.gifdot.gifdot.gifdot.gif.
InBlock.gif        
//dot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gif
InBlock.gif        
//dot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gifdot.gif..
InBlock.gif
InBlock.gif
InBlock.gif        
//所有业务正确处理完成,提交事务,返回ture
InBlock.gif

InBlock.gif       ContextUtil.SetComplete();
InBlock.gif        
return true;
InBlock.gif
ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        ContextUtil.SetAbort();
//回滚事务
InBlock.gif
        throw;
ExpandedSubBlockEnd.gif      }

InBlock.gif      
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif       
// sc = null;
InBlock.gif
        dal = null;
InBlock.gif        ServiceDomain.Leave();
ExpandedSubBlockEnd.gif      }

InBlock.gif
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public  DataTable GetWorkerInfo()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      DAL.DalWorkerInfo dal 
= new DAL.DalWorkerInfo();
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
return dal.GetWorkerInfo();
ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
return null;
ExpandedSubBlockEnd.gif      }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

而应用层只需要调用业务层的方法,然后就不用去管了,所有的业务逻辑都交给业务层去处理

None.gif private   void  btnAdd_Click( object  sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif      BLL.BllWorkerInfo bll 
= new BLL.BllWorkerInfo();
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
if (bll.AddWorkerInfo(txtWorkerID.Text.Trim (), txtName.Text, int.Parse (txtAge.Text) ,txtTel.Text.Trim ()))
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          UpdateData();
InBlock.gif          MessageBox.Show(
"增加成功");
ExpandedSubBlockEnd.gif        }

InBlock.gif        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif          MessageBox.Show(
"增加失败");
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch (Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        MessageBox.Show(ex.Message);
ExpandedSubBlockEnd.gif      }

InBlock.gif      
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif 
ExpandedSubBlockEnd.gif      }

ExpandedBlockEnd.gif    }

None.gif    
void  UpdateData()
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif      BLL.BllWorkerInfo bll 
= new BLL.BllWorkerInfo();
InBlock.gif      
try
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
this.dataGridView1.DataSource = bll.GetWorkerInfo();
ExpandedSubBlockEnd.gif      }

InBlock.gif      
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif
ExpandedSubBlockEnd.gif      }

ExpandedBlockEnd.gif    }

None.gif  }

看完上面的介绍是不是觉得一个三层架构的设计其实很简单,想必这样的代码不用看多久就能够马上看懂。同时采用了分层,以后维护也更加方便。就算业务改变了,也只需改变业务层的代码。
如果你是一个大型系统,将之变为一个分布式的系统也简单,改业务层的类从MarshalByRefObject派生,在服务器端,注册业务层类为远程对象,在客户端直接调用远程对象。
这个可以在Vs 2005中使用配置文件完成,稍加点代码就可以完成一个分布系统的发布。
可以写个Window服务程序,用来注册远程对象
只要加入:RemotingConfiguration.Configure("RemoteServer.exe.config", false);

None.gif <? xml version="1.0" encoding="utf-8"  ?>
None.gif
< configuration >
None.gif  
< connectionStrings >
None.gif    
< add  name ="ArchDesign.Properties.Settings.DataBaseConnectionString"
None.gif        connectionString
="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
None.gif        providerName
="System.Data.SqlClient"   />
None.gif    
< add  name ="SqlConnectionString"
None.gif          connectionString
="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
None.gif          providerName
="System.Data.SqlClient"   />
None.gif  
</ connectionStrings >
None.gif  
< system .runtime.remoting  >
None.gif    
< application  name ="RemoteHostService" >
None.gif      
< service >
None.gif        
< wellknown   type ="BLL.BllWorkerInfo,BllWorkerInfo"  objectUri ="BllWorkerInfo"  mode ="SingleCall"   />
None.gif      
</ service >
None.gif      
< channels >
None.gif        
<!-- <channel type="System.Runtime.Remoting.Channels.Tcp,System.Runtime.Remoting" port="9999"  /> -->
None.gif        
< channel  ref ="tcp"  port ="9999" />
None.gif        
<!-- <channel ref="http" port="8888" />
None.gif        <channel ref="ipc" portName="testPipe" />
-->
None.gif      
</ channels >
None.gif    
</ application >
None.gif  
</ system.runtime.remoting >
None.gif
</ configuration >


客户端可以直接用New调用远程对象,在程序开始是运行配置文件:RemotingConfiguration.Configure("RemoteServer.exe.config", false);

None.gif <? xml version="1.0" encoding="utf-8"  ?>
None.gif
< configuration >
None.gif    
< configSections >
None.gif    
</ configSections >
None.gif    
< connectionStrings >
None.gif        
< add  name ="ArchDesign.Properties.Settings.DataBaseConnectionString"
None.gif            connectionString
="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
None.gif            providerName
="System.Data.SqlClient"   />
None.gif      
< add  name ="SqlConnectionString"
None.gif            connectionString
="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\DataBase.mdf;Integrated Security=True;User Instance=True"
None.gif            providerName
="System.Data.SqlClient"   />
None.gif    
</ connectionStrings >
None.gif  
< system .runtime.remoting  >
None.gif    
< application  name ="RemoteHostClient" >
None.gif      
< client >
None.gif        
< wellknown  type ="BLL.BllWorkerInfo,BllWorkerInfo"  url ="tcp://localhost:9999/BllWorkerInfo"   />   
None.gif      
</ client >
None.gif      
< channels >
None.gif      
</ channels >
None.gif      
</ application >
None.gif  
</ system.runtime.remoting >
None.gif
</ configuration >

一个简单的三层结构的架构就达起来了,可能其中还有某些不足的地方,例如由于保存一个客户端只要一个数据连接,都从一个数据低层派生,如果是多个数据库那就有问题。还有就是如果一个业务参数过多,每个参数写起来也很麻烦,修改起来还得看下参数的顺序,可以把他改为类对象,每个数据表对应一个类,类似
pet Shop的设计,同时可以将业务层写个接口,只提供接口给客户端调用,这个可以同时开发。总之我觉得整个设计一个就是简单,像事务处理,业务逻辑这样一写都非常明了,以后维护起来也很方便。如果大家觉得有更好的简洁的设计欢迎大家指点宝贵的意见,相互学习。
/Files/zhang3533/ArchDesign.rar

转载于:https://www.cnblogs.com/ruinet/archive/2007/06/28/798819.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值