zoukankan      html  css  js  c++  java
  • 循序渐进开发WinForm项目(2)--项目代码的分析

     

    1、数据访问接口的定义

    上面我们分析了实体类的定义,本节继续分析其他部分的内容,如数据访问接口成的定义如下所示。

    复制代码
    namespace WHC.TestProject.IDAL
    {
        /// <summary>
        /// 客户信息
        /// </summary>
        public interface ICustomer : IBaseDAL<CustomerInfo>
        {
        }
    }
    复制代码

    这里面的代码很简单,没有多余的代码行,那么里面究竟发生了什么呢,其中的IBaseDAL又是什么定义呢?

    其实,IBaseDAL就是定义了很多我们开发用到的基础接口,如标准的增删改查,以及衍生出来的一些其他接口,如分页查询,条件查询等接口内容。这个ICustomer就是用来定义一些除了标准接口不能实现外的业务接口。

    IBaseDAL通过传入一个实体类,从而方便给基类接口提供强类型的数据类型指定,提高我们的开发效率,减少出错的机会。

    我们可以在VS里面查看IBaseDAL的定义,如下所示:

    可以看到里面很多相关的接口定义,有返回实体T的,也有返回List<T>的,还有DataTable类型等等,这些基础接口,经过我们多个项目的应用实践,已逐步稳定并能够提供很好的接口支持,方便我们快速调用处理。

    即使我们在没有实现任何业务接口的情况下,仅仅利用标准的基类API,也基本上能够完成绝大多数的数据操作功能了。

    2、数据访问接口实现类的定义

     我们分析完IDAL的数据访问接口成的定义后,继续了解一下,如何基于这个接口进行访问层的实现设计的。数据访问的实现层在项目中的位置如下所示(以基于SqlServer的DALSQL层进行分析)。

     

    它的类代码定义如下所示。

    复制代码
    namespace WHC.TestProject.DALSQL
    {
        /// <summary>
        /// 客户信息
        /// </summary>
        public class Customer : BaseDALSQL<CustomerInfo>, ICustomer
        {
    复制代码

    数据访问接口实现层和接口定义层一样,都有一个基类,如基于SqlServer实现的基类为BaseDALSQL,这个基于SqlServer的数据访问基类,它也是继承自一个超级基类(大多数的实现在这里)AbstractBaseDAL。他们之间的继承关系如下所示

    而我们刚才在项目工程的图里面看到,BaseDALSQL、IBaseDAL、AbstractBaseDAL这些类库由于具有很大的通用性,为了减少在不同的项目中进行复制导致维护问题,因此我们全部把这些经常使用到的基类或者接口,抽取到一个独立的类库里面,为了和普通的DotNET公用类库命名进行区分(WHC.Framework.Commons),我们把它命名为WHC.Framework.ControlUtil。

    BaseDALSQL基类的定义如下所示。

    这样做的好处是,在所有的模块里面,避免复制导致的版本维护问题,同时也减少代码的重复生成,增量生成的全部代码,可以一次性复制到整个项目工程里面,而不会导致基础类库的替换,因为这些基类不在生成目录里面,所有生成的类文件,都是和业务表相关的,如下所示。

    具体的数据访问实现类(如Customer),它把数据库信息转换为实体类,有一个函数,在代码生成的时候已经生成;同时在把实体类的属性保存到数据库也有一个类似CRM的映射关系,从而实现可空的字段获取和更新操作。

    复制代码
            /// <summary>
            /// 将DataReader的属性值转化为实体类的属性值,返回实体类
            /// </summary>
            /// <param name="dr">有效的DataReader对象</param>
            /// <returns>实体类对象</returns>
            protected override CustomerInfo DataReaderToEntity(IDataReader dataReader)
            {
                CustomerInfo info = new CustomerInfo();
                SmartDataReader reader = new SmartDataReader(dataReader);
                
                info.ID = reader.GetString("ID");
                info.Name = reader.GetString("Name");
                info.Age = reader.GetInt32("Age");
                info.Creator = reader.GetString("Creator");
                info.CreateTime = reader.GetDateTime("CreateTime");
                
                return info;
            }
    
            /// <summary>
            /// 将实体对象的属性值转化为Hashtable对应的键值
            /// </summary>
            /// <param name="obj">有效的实体对象</param>
            /// <returns>包含键值映射的Hashtable</returns>
            protected override Hashtable GetHashByEntity(CustomerInfo obj)
            {
                CustomerInfo info = obj as CustomerInfo;
                Hashtable hash = new Hashtable(); 
                
                hash.Add("ID", info.ID);
                 hash.Add("Name", info.Name);
                 hash.Add("Age", info.Age);
                 hash.Add("Creator", info.Creator);
                 hash.Add("CreateTime", info.CreateTime);
                     
                return hash;
            }
    复制代码

    3、业务逻辑层的实现分析

     分析完成了数据访问层的接口和实现类后,我们来进一步看看业务逻辑层的实现分析,由于数据访问层的本意是基于特定的数据库实现,因此业务逻辑层就是抽象不同的数据库,让它们根据配置,指向不同的数据库实现类,从而实现多数据库的支持。

    复制代码
    namespace WHC.TestProject.BLL
    {
        /// <summary>
        /// 客户信息
        /// </summary>
        public class Customer : BaseBLL<CustomerInfo>
        {
            public Customer() : base()
            {
                base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
            }
        }
    }
    复制代码

    业务逻辑层的代码也很简单,在构造函数里面Init一下即可,之所以使用这个Init操作,其实为了确定BLL层的业务对象名称和指定在哪个程序集里面进行构造的需要,让给基类进行必要的创建工作。

    在BaseBLL的Init函数里面,我们根据子类传入的相关参数,由于我们约定了数据访问类的命名空间,因此只根据数据库配置的不同需要,替换部分名称,就可以具体的构造出一个数据访问类了。

    复制代码
                #region 根据不同的数据库类型,构造相应的DAL层
                AppConfig config = new AppConfig();
                string dbType = config.AppConfigGet("ComponentDbType");
                if (string.IsNullOrEmpty(dbType))
                {
                    dbType = "sqlserver";
                }
                dbType = dbType.ToLower();
    
                string DALPrefix = "";
                if (dbType == "sqlserver")
                {
                    DALPrefix = "DALSQL.";
                }
                else if (dbType == "access")
                {
                    DALPrefix = "DALAccess.";
                }
                else if (dbType == "oracle")
                {
                    DALPrefix = "DALOracle.";
                }
                else if (dbType == "sqlite")
                {
                    DALPrefix = "DALSQLite.";
                }
                else if (dbType == "mysql")
                {
                    DALPrefix = "DALMySql.";
                }
                #endregion
    
                this.dalName = bllFullName.Replace(bllPrefix, DALPrefix);//替换中级的BLL.为DAL.,就是DAL类的全名
                baseDal = Reflect<IBaseDAL<T>>.Create(this.dalName, dalAssemblyName);//构造对应的DAL数据访问层的对象类
    复制代码

    这样精确构造出来的数据库访问访问对象,并把它转换为基类接口,那么就可以在BaseBLL类里的基类接口进行调用了。

    而构造业务对象,通过BLLFactory<T>的泛型工厂,更能够精确构造出对应的业务对象类,这样构造出来的对象具有强类型,非常方便使用。

    以上就是业务逻辑层,数据访问层和数据访问接口层的设计关系,为了高效进行开发工作,我们一定要使用强类型的接口调用,这样可以大大减少出错机会,而返回的基类接口,由于传入了特定的具体类型T,也能够构造出强类型的列表或者对象。因此,合理利用泛型,能够是我们的开发体验更加美好,更加高效。 

  • 相关阅读:
    基于Python的TCP阻塞式echo服务器
    Memcache仅仅支持简单数据类型
    Memcached(七)Memcached的并发实例
    Memcached(六)Memcached的并发实例
    Memcached(五)Memcached的并发实例
    Tcl/Tk的安装(转)
    centos6.5下安装Scipy工具包
    Mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'问题的解决
    mysql启动失败解决方案
    Linux更换python版本
  • 原文地址:https://www.cnblogs.com/ysz12300/p/5283540.html
Copyright © 2011-2022 走看看