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

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

1、 实体层(定义一个空的基类,其他实体类继承之,主要是为了利用泛型操作,用途下面细说)

    public class BaseEntity
    {    
    }


    public class EquipmentInfo : BaseEntity
    {    
        Field Members

        Property Members

    }

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


    /// <summary>
    /// 数据访问层的基类
    /// </summary>
    public abstract class BaseDAL<T> : IBaseDAL<T> where T : BaseEntity, new()
    {
}

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


    /// <summary>
    /// 一些基本的,作为辅助函数的接口
    /// </summary>
    public interface IBaseDAL<T> where T : BaseEntity
    {
        /// <summary>
        /// 查询数据库,检查是否存在指定键值的对象
        /// </summary>
        /// <param name="recordTable">Hashtable:键[key]为字段名;值[value]为字段对应的值</param>
        /// <returns>存在则返回<c>true</c>,否则为<c>false</c>。</returns>
        bool IsExistKey(Hashtable recordTable);

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

        /// <summary>
        /// 获取数据库中该对象的最大ID值
        /// </summary>
        /// <returns>最大ID值</returns>
        int GetMaxID();

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


        /// <summary>
        /// 插入指定对象到数据库中
        /// </summary>
        /// <param name="obj">指定的对象</param>
        /// <returns>执行成功返回True</returns>
        bool Insert(T obj);

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

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

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

        返回集合的接口
    }

细看上面代码,会发现由一个PagerInfo 的类,这个类是用来做分页参数传递作用的,根据这个参数,你可以知道具体返回那些关心的记录信息,这些记录又转换为强类型的List<T>集合。
再看看数据库访问基类的具体实现代码吧:
    /// <summary>
    /// 数据访问层的基类
    /// </summary>
    public abstract class BaseDAL<T> : IBaseDAL<T> where T : BaseEntity, new()
    {
        构造函数

        通用操作方法

        对象添加、修改、查询接口

        返回集合的接口
        
        子类必须实现的函数(用于更新或者插入)
        
        IBaseDAL接口
    }

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

    public interface IEquipment : IBaseDAL<EquipmentInfo>
    {
    }

    public class Equipment : BaseDAL<EquipmentInfo>, IEquipment
    {
        对象实例及构造函数
}

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

protected override EquipmentInfo DataReaderToEntity(IDataReader dataReader)

protected override Hashtable GetHashByEntity(EquipmentInfo obj)

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


    public class Equipment : BaseDAL<EquipmentInfo>, IEquipment
    {
        对象实例及构造函数

        /// <summary>
        /// 将DataReader的属性值转化为实体类的属性值,返回实体类
        /// </summary>
        /// <param name="dr">有效的DataReader对象</param>
        /// <returns>实体类对象</returns>
        protected override EquipmentInfo DataReaderToEntity(IDataReader dataReader)
        {
            EquipmentInfo equipmentInfo = new EquipmentInfo();
            SmartDataReader reader = new SmartDataReader(dataReader);
            
            equipmentInfo.ID = reader.GetInt32("ID");
            equipmentInfo.PartID = reader.GetString("PartID");
            equipmentInfo.Name = reader.GetString("Name");
            equipmentInfo.EquipmentType = reader.GetString("EquipmentType");
            equipmentInfo.Specification = reader.GetString("Specification");
            equipmentInfo.Manufacturer = reader.GetString("Manufacturer");
            equipmentInfo.Picture = reader.GetBytes("Picture");
            equipmentInfo.ApplyEquipment = reader.GetString("ApplyEquipment");
            equipmentInfo.BuyAmount = reader.GetInt32("BuyAmount");
            equipmentInfo.BuyDate = reader.GetDateTime("BuyDate");
            equipmentInfo.Status = reader.GetString("Status");
            equipmentInfo.UserName = reader.GetString("UserName");
            equipmentInfo.SafeNumber = reader.GetInt32("SafeNumber");
            equipmentInfo.Note = reader.GetString("Note");
            
            return equipmentInfo;
        }

        /// <summary>
        /// 将实体对象的属性值转化为Hashtable对应的键值
        /// </summary>
        /// <param name="obj">有效的实体对象</param>
        /// <returns>包含键值映射的Hashtable</returns>
        protected override Hashtable GetHashByEntity(EquipmentInfo obj)
        {
            EquipmentInfo info = obj as EquipmentInfo;
            Hashtable hash = new Hashtable(); 
            
            hash.Add("ID", info.ID);
            hash.Add("PartID", info.PartID);
            hash.Add("Name", info.Name);
            hash.Add("EquipmentType", info.EquipmentType);
            hash.Add("Specification", info.Specification);
            hash.Add("Manufacturer", info.Manufacturer);
            hash.Add("Picture", info.Picture);
            hash.Add("ApplyEquipment", info.ApplyEquipment);
            hash.Add("BuyAmount", info.BuyAmount);
            hash.Add("BuyDate", info.BuyDate);
            hash.Add("Status", info.Status);
            hash.Add("UserName", info.UserName);
            hash.Add("SafeNumber", info.SafeNumber);
            hash.Add("Note", info.Note);
                
            return hash;
        }
    }

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

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

时间: 2024-10-26 12:19:21

一个分层架构设计的例子(1)的相关文章

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

接着上一篇关于分层架构的讨论,一个分层架构设计的例子(1).上篇介绍了实体类(Entity).数据库访问类(DAL).数据访问接口(IDAL)的相关设计,本篇主要讨论下面几个部分内容:业务逻辑层.缓存机制.界面层等方面.业务逻辑层,主要是业务逻辑基类的设计,由于数据库访问类(DAL)的基类封装了大量的操作实现,因此,业务逻辑层的主要工作是进一步封装对底层访问接口的实现,如下所示.     public class BaseBLL<T> where T : BaseEntity, new()  

Haproxy负载均衡集群架构设计的例子

公司最近有一个项目由于用户担心一台单机无法承担最多用户量的使用,要求上应用集群.我们根据应用情况设计了应用集群架构. 架构图如下: 部署应用集群的特点: 1. 前端代理负载均衡 因用户环境基础架构采用虚拟化集群平台,服务器均采用虚拟机实现,所以设计时采用单台Haproxy来实现. 前端选用haproxy:有一最大的特点HTTP第7层键康状态检查,与我们实际需要一致,因经常有应用压力大,应用无法响应的情况,正好通过这一个特性进行健康状态检查,保证用户透明访问.之前有采用haporxy的主备模式做双

【架构篇】Android移动app架构设计浅谈

前言 架构,又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计. 软件架构设计目标: 1.可靠性(Reliable).软件架构的可靠是产品设计的前提. 2.安全性(Secure).软件架构的安全性是产品可持续发展的条件. 3.可扩展性(Scalable).软件架构必须能够不同的功能需求情况下,支持可扩散性. 4.可定制化(Customizable).同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整. 5.可伸缩 (Extensible).在新技术出现

iOS开发入门:移动平台架构设计

低耦合企业级系统架构设计 我们往往称JavaEE或.Net 开发的产品为"系统",而移动平台(主要是:Android.iOS和Window Phone)开发的产品为"应用"."系统"比较复杂,需要架构设计,而"应用"相对比较简单,这是不是意味着我们不需要考虑架构问题呢? 我 们首先了解一下企业级系统架构设计.软件设计的原则是提高软件系统的"可复用性"和"可扩展性",系统架构设计采用层次划

iOS开发那些事-移动平台架构设计

低耦合企业级系统架构设计 我们往往称JavaEE或.Net 开发的产品为"系统",而移动平台(主要是:Android.iOS和Window Phone)开发的产品为"应用"."系统"比较复杂,需要架构设计,而"应用"相对比较简单,这是不是意味着我们不需要考虑架构问题呢?   我们首先了解一下企业级系统架构设计.软件设计的原则是提高软件系统的"可复用性"和"可扩展性",系统架构设计采用层次

Swift项目开发实战-基于分层架构的多版本iPhone计算器-直播公开课

Swift项目开发实战-基于分层架构的多版本iPhone计算器-直播公开课 本课程采用QQ群直播方式进行直播,价值99元视频课程免费直播.完整的基于Swift项目实战,手把手教你做一个Swift版iPhone计算器.(直播过程也有惊喜!)直播QQ群:362298485(直播时点击群视频即可进入直播课堂)直播时间:8月26日(周二),9月2日(周四),每天20:00-22:00欢迎咨询客服QQ:1575716557直播后希望继续深入学习了解本课程可在51CTO学院购买本课程,定价99元.购买课程更

一起谈.NET技术,走向ASP.NET架构设计——第四章—业务层分层架构(中篇)

在上一篇文章中,我们讨论了两种组织业务逻辑的模式:Transaction Script和Active Record.在本篇中开始讲述Domain Model和Anemic Model. Domain Model 在开发过程中,我们常常用Domain Model来对目标的业务领域建模.通过Domain Model建模的业务类代表了目标领域中的一些概念.而且,我们会看到通过Domain Model建模的一些对象模拟了业务活动中的数据,有的对象还反映了一些业务规则. 我们就来看看电子商务系统的开发,在

.NET应用架构设计—重新认识分层架构(现代企业级应用分层架构核心设计要素)

阅读目录: 1.背景介绍 2.简要回顾下传统三层架构 3.企业级应用分层架构(现代分层架构的基本演变过程) 3.1.服务层中应用契约式设计来解决动态条件不匹配错误(通过契约式设计模式来将问题在线下暴露出来) 3.2.应用层中的应用控制器模式(通过控制器模式对象化应用层的职责) 3.3.业务层中的命令模式(事务脚本模式的设计模式运用,很好的隔离静态数据) 4.服务层作为SOA契约公布后DTO与业务层的DomainModel共用基本的原子类型 5.两种独立业务层职责设计方法(可以根据具体业务要求来搭

DotNET企业架构应用实践-实例架构设计中的业务分层-提取独立的业务层

      说明一下,原本的思路是通过一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录相关的文章来逐步讲解基于AgileEAS.NET平台进行应用开发的文章,但是在进行案例讲解的过程,我们不得不扯到有关于AgileEAS.NET平台进行应用开发的架构设计方面的东西,我就把一些与架构有关的文章分离出来讲,了,我是基于AgileEAS.NET平台的应用开发实例来讲解架构设计,所以本文应该还有个副标题"一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-提取独立