一个分层架构设计的例子(1)

简介:
一般来说,对系统的分层,一般都需要下面几个层:实体层(Entity)、数据访问层(DAL)、业务逻辑层(BLL)、界面层(UI);而数据访问层,一般也会加入一个接口层(IDAL)。
在其中的实体层,一般是根据数据库进行映射外加入注释等,技术含量不大,在此一笔带过;数据库访问层和业务逻辑层,是关键之所在,因为这里好的设计,会利用很多基类的操作,减少很多代码和重复劳动;界面层,不管是WebForm还是WinForm,都是尽可能少的逻辑代码或者SQL语句在其中,好的项目可能会利用一些优秀的控件进去,提高体验,减少代码。另外,由于一些创建操作费时费资源,一般还需要把可重复利用的资源缓存起来,提高性能。
先给大家预览下项目的框架,再一层层分析讨论:
EnterpriseLib.jpg

1、 实体层(定义一个空的基类,其他实体类继承之,主要是为了利用泛型操作,用途下面细说)
None.gif      public   class  BaseEntity
ExpandedBlockStart.gif    
{    
ExpandedBlockEnd.gif    }
复制代码
None.gif      public   class  EquipmentInfo : BaseEntity
ExpandedBlockStart.gif    
{    
ContractedSubBlock.gif        
Field Members
InBlock.gif
ContractedSubBlock.gif        
Property Members
InBlock.gif
ExpandedBlockEnd.gif    }
复制代码

2、 数据库访问层,数据访问层的关键是数据访问基类的设计,基类实现大多数数据库的日常操作,如下:

复制代码
ExpandedBlockStart.gif      /// <summary>
InBlock.gif    
/// 数据访问层的基类
ExpandedBlockEnd.gif    
/// </summary>

None.gif      public   abstract   class  BaseDAL < T >  : IBaseDAL < T >   where  T : BaseEntity,  new ()
ExpandedBlockStart.gif    
{
ExpandedBlockEnd.gif}
复制代码

BaseEntity就是实体类的基类,IBaseDAL是定义的数据访问基类接口,包含各种常用的操作定义;因此BaseDAL就是要对各种操作的进行实现,实现接口越多,将来继承类的重用程度就越高。
以上通过泛型<T> ,我们就可以知道实例化那个具体访问类的信息了,可以实现强类型的函数定义。

复制代码
ExpandedBlockStart.gif      /// <summary>
InBlock.gif    
/// 一些基本的,作为辅助函数的接口
ExpandedBlockEnd.gif    
/// </summary>

None.gif      public   interface  IBaseDAL < T >   where  T : BaseEntity
ExpandedBlockStart.gif    
{
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 查询数据库,检查是否存在指定键值的对象
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="recordTable">Hashtable:键[key]为字段名;值[value]为字段对应的值</param>
ExpandedSubBlockEnd.gif        
/// <returns>存在则返回<c>true</c>,否则为<c>false</c></returns>

InBlock.gif        bool IsExistKey(Hashtable recordTable);
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 查询数据库,检查是否存在指定键值的对象
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="fieldName">指定的属性名</param>
InBlock.gif        
/// <param name="key">指定的值</param>
ExpandedSubBlockEnd.gif        
/// <returns>存在则返回<c>true</c>,否则为<c>false</c></returns>

InBlock.gif        bool IsExistKey(string fieldName, object key);
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 获取数据库中该对象的最大ID值
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <returns>最大ID值</returns>

InBlock.gif        int GetMaxID();
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 根据指定对象的ID,从数据库中删除指定对象
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="key">指定对象的ID</param>
ExpandedSubBlockEnd.gif        
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>

InBlock.gif        bool DeleteByKey(string key);
InBlock.gif        
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 根据条件,从数据库中删除指定对象
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="condition">删除记录的条件语句</param>
ExpandedSubBlockEnd.gif        
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>

InBlock.gif        bool DeleteByCondition(string condition);
InBlock.gif
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 插入指定对象到数据库中
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="obj">指定的对象</param>
ExpandedSubBlockEnd.gif        
/// <returns>执行成功返回True</returns>

InBlock.gif        bool Insert(T obj);
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 更新对象属性到数据库中
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="obj">指定的对象</param>
ExpandedSubBlockEnd.gif        
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>

InBlock.gif        bool Update(T obj, string primaryKeyValue);
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 查询数据库,检查是否存在指定ID的对象(用于整型主键)
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="key">对象的ID值</param>
ExpandedSubBlockEnd.gif        
/// <returns>存在则返回指定的对象,否则返回Null</returns>

InBlock.gif        T FindByID(int key);
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 查询数据库,检查是否存在指定ID的对象(用于字符型主键)
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="key">对象的ID值</param>
ExpandedSubBlockEnd.gif        
/// <returns>存在则返回指定的对象,否则返回Null</returns>

InBlock.gif        T FindByID(string key);
InBlock.gif
ContractedSubBlock.gif        
返回集合的接口
ExpandedBlockEnd.gif    }
复制代码

细看上面代码,会发现由一个PagerInfo 的类,这个类是用来做分页参数传递作用的,根据这个参数,你可以知道具体返回那些关心的记录信息,这些记录又转换为强类型的List<T>集合。
再看看数据库访问基类的具体实现代码吧:
ExpandedBlockStart.gif    /// <summary>
InBlock.gif    
/// 数据访问层的基类
ExpandedBlockEnd.gif    
/// </summary>

None.gif    public abstract class BaseDAL<T> : IBaseDAL<T> where T : BaseEntity, new()
ExpandedBlockStart.gif    {
ContractedSubBlock.gif        构造函数
InBlock.gif
ContractedSubBlock.gif        通用操作方法
InBlock.gif
ContractedSubBlock.gif        对象添加、修改、查询接口
InBlock.gif
ContractedSubBlock.gif        返回集合的接口
InBlock.gif        
ContractedSubBlock.gif        子类必须实现的函数(用于更新或者插入)
InBlock.gif        
ContractedSubBlock.gif        IBaseDAL接口
ExpandedBlockEnd.gif    }

3、具体的数据访问类
基类完成所有的操作了,对于具体的类将是一大福音,说明它的工作减少很多了,下面看看具体的实现过程。定义一个数据访问类接口,然后实现接口和继承基类即可。

None.gif      public   interface  IEquipment : IBaseDAL < EquipmentInfo >
ExpandedBlockStart.gif    
{
ExpandedBlockEnd.gif    }
None.gif      public   class  Equipment : BaseDAL < EquipmentInfo > , IEquipment
ExpandedBlockStart.gif    
{
ContractedSubBlock.gif        
对象实例及构造函数
ExpandedBlockEnd.gif}

其实这样就完成了,我们为了提高效率,重载两个函数的实现,避免基类的属性反射带来的性能损失,这两个函数看似很复杂,其实通过代码生成工具,生成起来也是毫不费功夫的。。

None.gif protected   override  EquipmentInfo DataReaderToEntity(IDataReader dataReader)
None.gif
None.gif
protected   override  Hashtable GetHashByEntity(EquipmentInfo obj)

因此最后的代码就变为下面

复制代码
None.gif      public   class  Equipment : BaseDAL < EquipmentInfo > , IEquipment
ExpandedBlockStart.gif    
{
ContractedSubBlock.gif        
对象实例及构造函数
InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 将DataReader的属性值转化为实体类的属性值,返回实体类
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="dr">有效的DataReader对象</param>
ExpandedSubBlockEnd.gif        
/// <returns>实体类对象</returns>

InBlock.gif        protected override EquipmentInfo DataReaderToEntity(IDataReader dataReader)
ExpandedSubBlockStart.gif        
{
InBlock.gif            EquipmentInfo equipmentInfo 
= new EquipmentInfo();
InBlock.gif            SmartDataReader reader 
= new SmartDataReader(dataReader);
InBlock.gif            
InBlock.gif            equipmentInfo.ID 
= reader.GetInt32("ID");
InBlock.gif            equipmentInfo.PartID 
= reader.GetString("PartID");
InBlock.gif            equipmentInfo.Name 
= reader.GetString("Name");
InBlock.gif            equipmentInfo.EquipmentType 
= reader.GetString("EquipmentType");
InBlock.gif            equipmentInfo.Specification 
= reader.GetString("Specification");
InBlock.gif            equipmentInfo.Manufacturer 
= reader.GetString("Manufacturer");
InBlock.gif            equipmentInfo.Picture 
= reader.GetBytes("Picture");
InBlock.gif            equipmentInfo.ApplyEquipment 
= reader.GetString("ApplyEquipment");
InBlock.gif            equipmentInfo.BuyAmount 
= reader.GetInt32("BuyAmount");
InBlock.gif            equipmentInfo.BuyDate 
= reader.GetDateTime("BuyDate");
InBlock.gif            equipmentInfo.Status 
= reader.GetString("Status");
InBlock.gif            equipmentInfo.UserName 
= reader.GetString("UserName");
InBlock.gif            equipmentInfo.SafeNumber 
= reader.GetInt32("SafeNumber");
InBlock.gif            equipmentInfo.Note 
= reader.GetString("Note");
InBlock.gif            
InBlock.gif            
return equipmentInfo;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gif        
/// <summary>
InBlock.gif        
/// 将实体对象的属性值转化为Hashtable对应的键值
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="obj">有效的实体对象</param>
ExpandedSubBlockEnd.gif        
/// <returns>包含键值映射的Hashtable</returns>

InBlock.gif        protected override Hashtable GetHashByEntity(EquipmentInfo obj)
ExpandedSubBlockStart.gif        
{
InBlock.gif            EquipmentInfo info 
= obj as EquipmentInfo;
InBlock.gif            Hashtable hash 
= new Hashtable(); 
InBlock.gif            
InBlock.gif            hash.Add(
"ID", info.ID);
InBlock.gif            hash.Add(
"PartID", info.PartID);
InBlock.gif            hash.Add(
"Name", info.Name);
InBlock.gif            hash.Add(
"EquipmentType", info.EquipmentType);
InBlock.gif            hash.Add(
"Specification", info.Specification);
InBlock.gif            hash.Add(
"Manufacturer", info.Manufacturer);
InBlock.gif            hash.Add(
"Picture", info.Picture);
InBlock.gif            hash.Add(
"ApplyEquipment", info.ApplyEquipment);
InBlock.gif            hash.Add(
"BuyAmount", info.BuyAmount);
InBlock.gif            hash.Add(
"BuyDate", info.BuyDate);
InBlock.gif            hash.Add(
"Status", info.Status);
InBlock.gif            hash.Add(
"UserName", info.UserName);
InBlock.gif            hash.Add(
"SafeNumber", info.SafeNumber);
InBlock.gif            hash.Add(
"Note", info.Note);
InBlock.gif                
InBlock.gif            
return hash;
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }
复制代码

文章太长,下面关于逻辑层、缓存、界面部分的设计在下一篇文章中介绍。
 以上所引用的代码是通过代码生成工具Database2Sharp自动生成(http://www.iqidi.com/Database2Sharp.htm),选择EnterpriseLibrary架构即可。
Database2Sharp_Enterprise.jpg

 本文转自博客园伍华聪的博客,原文链接:一个分层架构设计的例子(1),如需转载请自行联系原博主。



目录
相关文章
|
2月前
|
负载均衡 关系型数据库 应用服务中间件
高可用系列文章之二 - 传统分层架构技术方案
高可用系列文章之二 - 传统分层架构技术方案
|
7月前
|
前端开发 Java Spring
架构设计的分层架构
架构设计的分层架构
|
1月前
|
分布式计算 API 数据处理
Flink【基础知识 01】(简介+核心架构+分层API+集群架构+应用场景+特点优势)(一篇即可大概了解flink)
【2月更文挑战第15天】Flink【基础知识 01】(简介+核心架构+分层API+集群架构+应用场景+特点优势)(一篇即可大概了解flink)
60 1
|
6月前
|
缓存 运维 网络协议
掌握网络架构核心!了解为什么要分层
掌握网络架构核心!了解为什么要分层
23 0
|
2月前
|
存储 自然语言处理 前端开发
软考实践之分层架构思想的理论和应用实践
软考实践之分层架构思想的理论和应用实践
222 0
|
2月前
|
消息中间件 前端开发 测试技术
DDD - 分层架构:有效降低层与层之间的依赖
DDD - 分层架构:有效降低层与层之间的依赖
|
3月前
|
XML Dubbo Java
【面试问题】Dubbo 的整体架构设计有哪些分层?
【1月更文挑战第27天】【面试问题】Dubbo 的整体架构设计有哪些分层?
|
3月前
|
存储 分布式计算 数据挖掘
数仓分层架构
数仓分层架构
74 0
|
3月前
|
Linux C语言 SoC
Linux驱动的软件架构(二):设备驱动的分层思想
Linux驱动的软件架构(二):设备驱动的分层思想
83 0
|
4月前
|
存储 数据采集 大数据
大数据必知必会系列——数仓分层架构及三层架构流程[新星计划]
大数据必知必会系列——数仓分层架构及三层架构流程[新星计划]
111 0