Winform开发框架的业务对象统一调用方式

在这个纷繁的社会里面,统一性的特点能够带来很多高效的产出、牢固的记忆,这种特征无论对于企业、个人的开发工作,知识的传承都有着非常重要的作用,Winfrom框架本身就是基于这个理念而生,从统一的数据库设计规则开始,统一的项目格局,统一的业务类、数据访问类、实体类继承关系,再到统一的公用类库,统一的权限管理模块,统一的字典管理模块,统一的附件管理...,理解这些理念和规则后,再来个终极的统一,框架代码快速生成--Database2Sharp代码生成工具。所有的框架(包括传统Winform开发框架、WCF开发框架、混合式开发框架、Web开发框架)都融合到这里来,统一整合各种看似零散,实则高度渗透的模块,统一的步伐除了时间、效力外,带来给我更多的馈赠。本文主要介绍我的Winform框架(也包括其他框架的特点)的业务对象统一调用的方式,介绍如何通过BLLFactory或者CallerFactory的公用类库来实现各种业务对象的创建工作。

1、BLLFactory的对象统一调用规则

在我的框架里面,所有的业务类调用都是以BLLFactory入口进行开始创建,传递业务对象进去即可创建,这种统一入口的方式能够方便记忆,并减少代码,更重要的是能够很好把一些如缓存规则、创建规则封装起来,简化代码。BLLFactory的创建示意图如下所示。

既然是统一调用规则方式,那么BLLFactory的类库就应该提升到公用类库的级别,所以提供Winform框架支持的公用类库如下所示。

当然,为了减少代码,提高开发效率,整体的框架处处体现了代码重用的规则,尽可能把重复的代码提取出来,因此还有很多如数据访问基类、业务访问基类、数据访问基类接口、实体基类等类库,结合泛型能够使我们的API更加统一化、强类型化,提高开发效率。由于BLLFactory是公用类库级别,所有独立开发的模块,也都是以该类库为统一入口,创建所必须的对象。

我们看看框架如何能够在纷繁复杂的类库里面,准确创建一系列的对象的。

BLLFactory业务对象工厂辅助类的代码如下所示。

    /// <summary>
    /// 对业务类进行构造的工厂类
    /// </summary>
    /// <typeparam name="T">业务对象类型</typeparam>
    public class BLLFactory<T> where T : class
    {
        private static Hashtable objCache = new Hashtable();
        private static object syncRoot = new Object();

        /// <summary>
        /// 创建或者从缓存中获取对应业务类的实例
        /// </summary>
        public static T Instance
        {
            get
            {
                string CacheKey = typeof(T).FullName;
                T bll = (T)objCache[CacheKey];  //从缓存读取  
                if (bll == null)
                {
                    lock (syncRoot)
                    {
                        if (bll == null)
                        {
                            bll = Reflect<T>.Create(typeof(T).FullName, typeof(T).Assembly.GetName().Name); //反射创建,并缓存
                            objCache.Add(typeof(T).FullName, bll);
                        }
                    }
                }
                return bll;
            }
        }
    }

其中利用了哈希表对象对创建的对象进行缓存,并进一步传递参数给Reflect公用类库,对指定对象全名、程序集的业务对象进行创建。

以上只是很薄的一层关系,一般我们都能够很容易理解,但是我们知道,每个业务对象类,还需要负责创建里面的数据访问基类(如IUser接口的数据访问基类userDal),我们来继续分析BaseBLL对象的工作逻辑,才能很好理解其中的关系。

    /// <summary>
    /// 用户信息业务管理类
    /// </summary>
    public class User : BaseBLL<UserInfo>
    {
        private IUser userDal;

        public User() : base()
        {
            base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
            this.userDal = (IUser)base.baseDal;
        }
        ..............................

    }

其中Init的函数接口定义如下,主要就是根据相关参数,构建数据不同的数据访问对象,如SqlServer的访问对象,或者Oracle的数据访问对象等。

        /// <summary>
        /// 参数赋值后,初始化相关对象
        /// </summary>
        /// <param name="bllFullName">BLL业务类的全名(子类必须实现),子类构造函数传入this.GetType().FullName</param>
        /// <param name="dalAssemblyName">数据访问层程序集的清单文件的文件名,不包括其扩展名,可使用Assembly.GetExecutingAssembly().GetName().Name</param>
        /// <param name="bllPrefix">BLL命名空间的前缀(BLL.)</param>
        void Init(string bllFullName, string dalAssemblyName, string bllPrefix = "BLL.")

由于数据访问也是基于反射方式(带缓存)创建,因此需要知道数据访问类的全名和对应的程序集,如果整合在一个项目工程里面,如我的框架结构代码所示,那么dalAssemblyName就是System.Reflection.Assembly.GetExecutingAssembly().GetName().Name了。其中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数据访问层的对象类

由于BLLFactory<T>通过传入指定的业务对象,成功创建后,会返回相关联的类的实例,因此接口的调用在设计时就知道了,也就是上面例子里面的BLLFactory<BLL.User>.Instance就是BLL.User类的实例,具有所有该类的接口方法,实现了强类型API的目的了。

下面就是该类在实际界面项目里面的使用例子代码。

                try
                {
                    UserInfo info = BLLFactory<User>.FindByID(currentID) as UserInfo;
                    if (info != null)
                    {
                        info = SetUserInfo(info);
                        BLLFactory<User>.Instance.Update(info, info.ID.ToString());
                        RefreshTreeView();

                        MessageDxUtil.ShowTips("资料保存成功");
                    }
                }
                catch (Exception ex)
                {
                    LogTextHelper.Error(ex);
                    MessageDxUtil.ShowError(ex.Message);
                }

2、CallerFactory的对象统一调用规则

CallerFactory对象是用于创建基于Facade层接口的业务对象,主要用在我的WCF开发框架、混合式开发框架里面,该对象的创建逻辑类似于BLLFactory,不过它创建的对象,可能是基于WCF客户代理的对象,也可能是对BLLFactory创建对象的进一步封装,以便实现宏观上的统一。如下图所示,CallerFactory处在下面框架结构图的中间部分,UI层的下面。

CallerFactory的调用代码例子如下所示。

                {
                    UserInfo info = CallerFactory<IUserService>.Instance.FindByID(currentID);
                    if (info != null)
                    {
                        info = SetUserInfo(info);
                        CallerFactory<IUserService>.Instance.Update(info, info.ID.ToString());
                        RefreshTreeView();

                        MessageDxUtil.ShowTips("资料保存成功");
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                    MessageDxUtil.ShowError(ex.Message);
                }

我们看到,虽然上面的代码是基于WCF的分布式应用,我们还是可以看到,这个调用的思路和方式,和传统Winform的BLLFactory如出一辙,能解决对象调用问题的同时,这样的操作方式,能够给我们学习框架提供了更好的统一模式,顺利切换,而且,从传统Winfrom开发框架的界面代码迁移到分布式应用的WCF开发上,界面代码的变化也是很有规律的,这就是统一模式的力量和奥妙所在。

和BLLFactory里面传入的业务层对象不同,这里CallerFactory里面传入的对象是Facade层的接口,那么它是如何知道我们要创建的对象,并把它转换为我们需要的接口的呢?

    /// <summary>
    /// 混合式框架或WCF框架中针对不同调用方式的工厂类(WCF或者Win调用)
    /// </summary>
    /// <typeparam name="T">接口类型</typeparam>
    public class CallerFactory<T>
    {
        private static Hashtable objCache = new Hashtable();
        private static object syncRoot = new Object();
        private static string callerNamespace = null;//Facade接口实现类的命名空间

        /// <summary>
        /// 创建或者从缓存中获取对应接口的实例
        /// </summary>
        public static T Instance
        {
            get
            {
                string CacheKey = typeof(T).FullName;
                T bll = (T)objCache[CacheKey];  //从缓存读取  
                if (bll == null)
                {
                    lock (syncRoot)
                    {
                        if (bll == null)
                        {
                            bll = CreateObject(); //反射创建,并缓存
                            if (bll != null)
                            {
                                objCache.Add(typeof(T).FullName, bll); //缓存BLL业务对象
                            }
                        }
                    }
                }
                return bll;
            }
        }

从上面的代码我们看到,这里的创建逻辑和BLLFactory很大程度的相同,只是细节部分,我使用了CreateObject 进行了隔离,放到独立的函数里面进行创建了。

CreateObject 函数主要逻辑就是根据WCF框架配置信息,到具体的程序集里面创建对应的对象实例,然后转换为Facade层接口,方便统一调用。这就是我WCF开发框架和混合式开发框架,统一调用接口进行通讯获取或提交数据的工作模式。

以上就是我Winform开发框架、WCF开发框架、混合式开发框架、Web开发框架里面所用到的两种方式的对象创建方式的说明,希望您能从统一的调用方式可以看到更多的奥妙及好处。

关于以上几种框架的定义说明,请查看下面图示的介绍,打开图示可以查看更多的框架介绍内容。

本文转自博客园伍华聪的博客,原文链接:Winform开发框架的业务对象统一调用方式,如需转载请自行联系原博主。



来源:https://yq.aliyun.com/articles/326682


智能推荐

Winform开发框架之混合型框架的剖析

我在随笔《Winform开发框架之框架演化》和《Winform开发框架之混合型框架的实现》都对Winform框架的变种,混合型框架进行了比较详细的介绍,本文继续上篇对混合型框架进行进一步的说明。 1、框架的扇出介绍 混合型框架为了支持WCF方式和传统访问数据库方式两种对数据操作的方式,有两个地方有扇出操作,一个是在界面上调用接口对象获取数据的时候有扇出操作,为了实现WCF方式和传统访问数据库方式的...

Winform开发框架之混合型框架的实现

我在之前一篇文章《Winform开发框架之框架演化》中,介绍了传统Winform开发框架、传统WCF开发框架、离线式WCF开发框架、混合式WCF开发框架,其中前面两种就是大家比较熟悉的框架了,后面的离线式WCF开发框架,我在《Winform开发之离线式WCF开发框架的实现介绍》一文中也做了阐述,离线式的WCF开发框架,可以看做为传统Winform开发框架+WCF同步模块而成,本文继续探讨这方面的框...

flex布局居中无效果注意是否设置了宽度

View 是flex布局;JDTouchable是flex:1;设置居中,  里面的两个View必须提供宽度,才能居中!...

mysql查询语句6:子查询

说明:当一个查询语句中又嵌套了另一个完整的select语句,则被嵌套的select语句称为子查询或内查询。外面的select语句称为主查询或外查询。 注:子查询不一定必须出现在select语句内部,只是出现在select语句内部的情况较多。 分类: 按子查询出现的位置进行分类: 1、select后面 要求:子查询的结果为单行单列(标量子查询) 2、from后面 要求:子查询的结果可以为多行多列 3...

go get被墙、速度太慢、没有反应以及go get下载的包无法导入的解决方案

go get被墙、速度太慢、没有反应的解决方案以及go get下载的包无法导入 由于国内网络的特殊环境,当我们在命令行中使用go get去获取第三方的库时,大概率没有任何反应,好在国内有一些代理,能够顺利解决这个问题,比如 Goproxy中国或者goproxy.io,具体操作在这两个网站里都有详细讲解,这里不在赘述,只是简单说说一些初学者在配置好代理之后可能遇到的坑。 首先就是,可能会有不少人发现...

猜你喜欢

配置HSRP

HSRP:热备份路由器协议(HSRP:Hot Standby Router Protocol),是cisco平台一种特有的技术,是cisco的私有协议。 原理:负责转发数据包的路由器称之为活动路由器(Active Router)。一旦主动路由器出现故障,HSRP 将**备份路由器(Standby Routers)取代主动路由器。HSRP 协议提供了一种决定使用主动路由器还是备份路由器的机制,并指定...

解决 ESXI6.x 主机时间(时区)显示不一致的问题

https://blog.51cto.com/jdonghong/1957118 也许我们应该根据作者的脚步进一步思考下去 近日由于设置ESXI计划任务,无意间发现了esxi服务器客服端时间和系统显示时间不一致的情况,导致了( 为了一致,通过SSH用命令修改了ESXI系统时间)虚拟机时间也不一致,最终导致虚拟服务器系统时间出错。 通过ssh进入EXSI6.X,可以看到系统时间相差4小时 相差大约4...

静态实验

AR1: GE0/0/1 :12.1.1.1/24 GE0/0/0 : 34.1.1.1/24 PC1 : 34.1.1.2/24 PC2 : 34.1.1.3/24 网关:34.1.1.1 配置: GE0/0/0: system-view进入系统模式 [Huawei]interface GigabitEthernet 0/0/0进入接口模式 [Huawei-GigabitEthernet0/0/...

8/7/21黑马32期Spring学习笔记01

ps:刘悦东老师讲的非常好,视频里也有配套的xmind文档,但是还是一边听课一边用Typora记了下自己认为比较重要的知识点。 spring1--一个可以装下任何对象的容器 一、安装环境 1.导入需要用的包和日志包 2.创建一个实体类对象 3.在src下创建一个applicationContext.xml进行配置 4.约束导入:<beans>里进行edit Namespace操作---...

信息熵与两种编码基础

文章目录 一、信息熵 二、香农-凡诺编码与霍夫曼编码 1.香农-凡诺编码 2.霍夫曼编码 三、RGB及BMP图像空间占用 一、信息熵 信息中排除了冗余后的平均信息量称为“信息熵” 信息熵是消除不确定性所需信息量的度量,也即未知事件可能含有的信息量 信息熵的定义公式 二、香农-凡诺编码与霍夫曼编码 一串消息包含A,B,C,D,E共5类符号,其内容是AABBBBAAAACCCC...

问答精选

How can I use SET in MYSQL to combine 2 values?

I wanted to SET a value into a VARCHAR but I don't understand how to combine it. Somehow I am losing the textpart "This is a test". Is this normal behaviour for MySQL, am I doing something w...

How to find the center in unity 2d?

I want to create 2d game. The game is similar to the Scale Puzzle. I've already created nearly all the functionality. Only the last remains. . This is example. And that's how I draw shapes. . I click ...

PHP question on how to display data?

How can I accomplish the following. For example lets say I already have a template that checks to see if the user has entered a link if not it will not display the link template if so display the link...

Allow match - special characters should only appear once in a row

I have a regex that cleans string of all unwanted characters. Allowed characters (matches) are A-Z a-z 0-9 - and / What i have so far works like it should: The only thing i cannot achieve is that - sh...

How to delete sheet from an existing excel file using JExel

I am trying to delete sheet from an existing excel file. can any one suggest how to do that. It depends what you're trying to achieve. Brute force method: the never Excel file format (*.XLSX) is just ...

相关问题

相关文章

热门文章

推荐文章

相关标签

推荐问答