三层开发中容易犯的错误(转)

三层开发中容易犯的错误(转)

我看了这片文章之后,发现自己所做的三层架构还是缺陷多多啊,所以把这片文章转下来……

前记:

相信大家对三层开发都已经耳熟能详,可是我却发现新公司的既有代码中有一些违背分层开发思想的东西,现在与大家分享这些错误,我们共勉之。

如果有人觉得对三层开发拿捏得不是太准,请参照李天平的文章:分层开发思想与小笼包,这篇文章用隐喻说明分层开发,是非常好的一篇文章。

正文:

1.界面层参与非界面逻辑,抢业务逻辑层的饭碗

什么是界面逻辑:<?XML:NAMESPACE PREFIX = O />

界面层应该有的逻辑就是显示的逻辑,例如根据逻辑结果显示某一个Panel不显示另外一个Panel,或者有一个数据集应该在界面上怎么呈现,这是界面层的逻辑

例子场景:

用户登录时首先验证用户输入的用户名是否有效,如果用户名有效,然后再验证用户输入的密码是否和用户名匹配,如果匹配则表示用户可以登录,增加用户的登录次数,然后将用户的信息写入Session中;否则返回错误。在这个过程中除了将用户信息写入Session这一步属于界面逻辑以外其他的操作都应该放在业务逻辑层。

错误代码示例:

ContractedBlock.gif
ExpandedBlockStart.gif
Code

private void buttonLogin_Click(object sender, EventArgs ev)
        {

            
string userName = textBoxUserName.Text;
            
string password = textPassword.Text;

            if (Business.Account.Exists(userName))
            {

                
bool success = Business.Account.Login(userName, password);
                
if (success)
                {

                    Business.Account.AddLoginTime(userName);

                    Session[user= new User(userName, password);
                    Redirect(
/);
                }
                
else
                {

                    
this.labelMessage.Text = 登录失败。;
                }
            }
            
else
            {

                
this.lableMessage.Text = 用户名不存在。;
            }
        }


分析:在上面的代码中一个UI层的一个事件中调用了三次rules层的方法:

Business.Account.Exists(userName)

Business.Account.Login(userName, password)

Business.Account.AddLoginTime(userName);

还附加有条件判断,这种方法在执行效果上面是没有什么错误的,可是却造成了逻辑前移;本来应该在逻辑层执行的判断放在了界面层,是不合适的。

2.数据访问层参与了大量的业务逻辑

这种现象经常出现在大量使用存储过程的系统中,将一大堆逻辑统统放在一个存储过程中实现了,乍一看可能很有效率,其实造成了系统结构的失调,给维护带来困难,数据访问层甚者数据库要抢逻辑层的饭碗了。

还以用户登录为例:

下面是业务逻辑层的登录方法:

ContractedBlock.gif
ExpandedBlockStart.gif
Code

//业务逻辑层的登录方法
        public int Login(string userName, string password) 
        {

            
return DataAccess.UserAccount.Login(userName, password);
        }

下面是数据层的登录方法:

ContractedBlock.gif
ExpandedBlockStart.gif
Code

//数据访问层的登录方法
        public int Login(string userName, string password)
        { 
            SqlParameter[] parameters 
= new SqlParameter[]
            {

                
// ……
            }
            
return SqlHelper.ExecuteProcedure(Login,parameters);
        }

下面是登录的存储过程:

ContractedBlock.gif
ExpandedBlockStart.gif
Code

CREATE PROC Login
            
@userName varchar(20),
            
@password varchar(20)
         
AS 
            
IF NOT EXISTS(SELECT * FROM UserAccount WHERE UserName = @userName)
                
RETURN 1
            
IF NOT EXISTS(SELECT * FROM UserAccount WHERE UserName = @userName AND password = @password)
                
RETURN 1
         
            
UPDATE UserAccount
            
SET LoginTimes = LoginTimes + 1
            
WHERE UserName = @userName
         
            
RETURN 0

分析:从上面三段代码中我们可以很显然得看到登录的业务逻辑已经全部被后移到了数据库的存储过程中。这样使用的三层结构就失去了意义,逻辑层名存实亡了;而数据库的压力会越来越大;我们修改业务逻辑的时候不是到逻辑层修改,而是要到数据库中去修改了。

3.将界面层上的数据组件(如SqlDataSource)作为参数传递到业务逻辑层去赋值

这样做的坏处很明显,本来是界面层依赖于业务逻辑层的,现在业务逻辑层反过来去依赖界面层的类,需要逻辑层引用System.Web命名空间,显然是错误的。

4.为了省事儿,不是直接将参数传递到业务逻辑层,而是通过HttpContext直接获得界面层应该传递的参数

例子:在系统设计的初期没有记录用户登录的IP地址,而到了后期发现了这个问题,要求纪录用户IP了,为了不修改业务逻辑层方法的定义,也不用修改界面层的调用方法,于是便写出了下面的代码:

ContractedBlock.gif
ExpandedBlockStart.gif
Code

public int Login(string userName, string password)
        {

            
string userIP = System.Web.HttpContext.Current.Request.UserHostAddress;
            
//follow is login steps
        }

这一点犯的错误和3中的错误相同,导致层之间形成了依赖环。

5.将事务处理放在数据访问层来做

事务处理应该放在业务逻辑层处理,原因是

1)事务的划分是根据业务逻辑来定义的,通常一个事务就代表完成了一个完整的逻辑操作;

2)一个业务逻辑可能有几个数据操作,修改几个表中的数据,而通常数据层的类的划分是根据数据库表来划分的,如果把事务处理放在数据访问层,那么业务层的方法需要调用两个以上的数据层方法时,就会出现执行两个事务的情况,显然这是不合理的。

总结:

1.在三层结构的划分中我们应该使三层各负其责,谁也不能越权,谁也不能懒惰,通常情况下,逻辑层应该在满足各负其责的条件下,尽可能的厚。

2.三层结构中的依赖关系很明确,界面层依赖于逻辑层,逻辑层依赖于数据访问层,不能互相依赖,而形成依赖环。

转载于:https://www.cnblogs.com/hackerxxw/archive/2008/08/07/1262537.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/111001.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 2019-1024杂记「建议收藏」

    今天1024,程序员的节日。这个节日对我来说从陌生到熟悉,在到自己成为节日的“主角”。想到自己选择的工作,程序员的工作,有时候真的是自己想干的嘛,其实我也不知道。由于历史的某个偶然的选择,成就了当下的必然结果。当下的某个选择,又会影响未来的发展。被时间裹挟向前一年复一年…

    2022年2月28日
    41
  • 关于ASP.NET编程中,GridView表格无法执行RenderControl()方法的问题

    关于ASP.NET编程中,GridView表格无法执行RenderControl()方法的问题当GridView表格控件设置了“自动排序”时,其RenderControl()方法运行时会报错。 

    2022年7月20日
    13
  • 我所喜欢的Drupal教程及资源

    我所喜欢的Drupal教程及资源本文转载于http://www.sayblog.me/the-drupal-tutorials-and-resourcesthat-i-like.html  Drupal是一个免费开源的内容管理系统(CMS),就跟Wordpress一样,不过要比Wordpress更具威力,也更复杂一些。Wordpress已经做得相当好了,甚至可以说已经很完美了,而且简单易用,所以它的用户比Dru

    2022年6月14日
    22
  • 谷歌浏览器无法上网问题解决方案_只有浏览器不能上网

    谷歌浏览器无法上网问题解决方案_只有浏览器不能上网今天清理垃圾时不小心删错了文件,导致谷歌浏览器一直无法上网,qq倒是能登陆。网上找了很多方法都没效果,什么取消代理服务器、管家网络修复、设置sfc什么通通都试过了。最后的解决办法是:1.win+r

    2022年8月1日
    3
  • netty 书籍_pdf怎么把书签变成目录

    netty 书籍_pdf怎么把书签变成目录Netty权威指南第2版带书签目录完整版下载地址:https://pan.baidu.com/s/12h96bKAdKEGXHdqOskK3nw扫码下面二维码关注公众号回复100019获取分享码本书目录结构如下:第1章Java的I/O演进之路1.1I/O基础入门1.2Java的I/O演进1.3总结第2章NIO入门2.1传统的BIO编程2.2伪异步I/O编程2.3NIO编程2.4AIO编程2.54…

    2022年10月2日
    0
  • 软件工程需求分析实验_实验设备管理系统需求分析

    软件工程需求分析实验_实验设备管理系统需求分析一、系统的问题描述1.系统简介每学年要对实验室设备使用情况进行统计、更新。其中:(1)对于已彻底损坏的做报废处理,同时详细记录有关信息。(2)对于由严重问题(故障)的要及时修理,并记录修理日期、设备名、编号、修理厂家、修理费用、责任人等。(3)对于急需修改但又缺少的设备,需以“申请表”的形式送交上级领导请求批准购买。新设备购入后要立即进行设备登记(包括类别、设备名、编号、型号、规格、单价、数量、购置日期、生产厂家、保质期和经办人等信息),同时更新申请表的内容。(4)随时对现有设备及其

    2022年10月13日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号