zoukankan      html  css  js  c++  java
  • 一个分层架构设计的例子(1)

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

    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架构即可。
    Database2Sharp_Enterprise.jpg

    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    OOP侧边分享按钮
    表格基础操作
    行为型模式之自定义语言的实现(解释器模式)
    行为型模式之请求发送者与接收者解耦(命令模式)
    行为型模式之请求的链式处理(职责链模式)
    Http、Socket、WebSocket之间联系与区别
    日期时间工具类DateTimeUtil(基于Java8的LocalDateTime)
    结构型模式之代理模式
    Java8 函数式接口@FunctionalInterface的使用说明
    结构型模式之实现对象的复用(享元模式)
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/1235576.html
Copyright © 2011-2022 走看看