65.9K
CodeProject 正在变化。 阅读更多。
Home

Web重构:会话包装器

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.78/5 (7投票s)

2005年8月28日

5分钟阅读

viewsIcon

50134

downloadIcon

380

使用重构改进现有 Web 应用程序(第一部分):会话包装器

引言

本文介绍了一种改进直接使用Session类的Web应用程序的简便方法。

实施这类改进称为“重构”。
因为它是专门针对Web应用程序的,所以我称之为“Web重构”。

首先,我将简要解释什么是重构,以及我所说的“Web重构”是什么意思。
其次,我将为直接使用Session对象的Web应用程序提供一个重构解决方案。

背景

“重构是以低风险、循序渐进、易于管理的方式改进现有代码设计的过程”。
重构旨在解决因以下原因导致的常见设计问题:

  • 重复代码;
  • 不清晰的代码;
  • 复杂的代码。

因此,Web重构是通过删除重复的、不清晰的和复杂的代码来改进现有Web应用程序的过程。

因为它涉及改进现有代码,所以我将给出一个可能的“之前” “之后”情况的示例。

重构之前

我认为会话值可以被视为全局变量。如果您直接使用许多这样的全局变量,那么您就违背了软件工程的基本原则之一:封装抽象。缺乏封装的缺点是显而易见的:每个使用这些未封装变量的人都需要完全理解所有可能的值和状态。在大多数情况下,意外错误发生只是时间问题。当这种情况发生时,您会注意到由于作用域是全局的,因此您的问题域也是全局的,您必须研究整个应用程序。

这样的代码通常(应该)看起来像这样

...

Int32 nUserID = -1;
if ( null != Session["userID"] ) {
  if ( Session["userID"] is Int32 ) {
    if ( 0 < Session["userID"] ) {
      nUserID = (Int32) Session["userID"]
    }
  }
}
if ( -1 == nUserID )
{
  throw new ApplicationException ( "Unexpected situation: userID invalid." );
}

this.doSomething( nUserID )
...

正如您所想,这是重构的绝佳候选者,因为它

  • 重复代码:无论何时您想使用这个全局变量,您在使用前都会重复检查;
  • 不清晰:这段代码使代码不清晰,因为它包含多行代码只是为了“使用”用户ID,这使得难以看出主代码的真正含义;
  • 复杂:要使用userID,您需要知道类型、默认值和会话键,并测试它是否存在。

 

重构之后

当您通过将逻辑封装在专门的类中来改进与会话相关的代码,从而实现所述解决方案时,代码质量会显著提高。

...

this.doSomething( CCurrentSession.UserID )
...

现在,任何人都可以看到应用此更改的优势

  • 重复代码:已删除;
  • 不清晰:代码没有不清晰之处(除了doSomething示例函数我想:-)
  • 复杂:获取会话用户ID不需要任何知识

 

实际重构过程

到目前为止,我们已经看到了“之前”和“之后”的情况。但是,我们实际需要做什么才能以易于管理、低风险、循序渐进的方式实现这一改进呢?

路线图:
实际实施此改进的路线图包括三个步骤: 

  1. 创建CCurrentSession类(我已包含一个示例,接下来将讨论);
  2. 实现您的第一个(静态)属性:为了平稳过渡,不要将所有会话对象一次性移动到包装类中,而要逐个移动。我将从逻辑最少且最容易测试的对象开始。这样您就可以轻松适应。
  3. 将直接使用会话对象的代码替换为使用CCurrentSession类。您应该能够通过搜索/替换来完成此操作。

 

CCurrentSession类

对于CCurrentSession类的初始版本,我定义了以下类型的属性

  • 如果之前未设置值,则具有默认值的属性;
  • 只有在之前已设置值后才能使用的属性;
  • 可以赋值为Null的属性;
  • 不能赋值为Null的属性;

这些类型已在四个不同的私有辅助函数中实现

  • private:GetValueOrDefault:获取具有默认值的属性的值;
  • private:GetMandatoryValue:获取必须具有先前设置的值才能使用的属性的值;
  • private:SetMandatoryValue:设置不能为Null的属性的值;
  • private:GetValue:从会话对象中指定键获取会话对象;
  • private:SetValue:将会话对象中特定键的对象设置为指定值;

访问会话状态

我将CCurrentSession类的属性公开为静态属性,这样我们就不必实例化对象。这非常简单,因为要访问会话状态对象,我使用静态“HttpContext.Current”属性,该属性返回当前HTTP请求的HttpContext对象。

最后,我使用了一个枚举来存储不同会话项的键值。这样我们就不必担心打字错误。

额外优势

  • 实现属性“惰性加载”的能力。想象一下,您的cCurrentSession类发展为包含更多逻辑,这些逻辑涉及通过计算或数据检索组合值。
  • 文档:通过使用CCurrentSession类,您可以集中会话属性的注释和文档文本。以前没有集中的方法来做到这一点。现在,例如,通过向属性和CCurrentSession类添加xml注释,您的注释将被像xDoc这样的文档工具获取。
  • 智能感知:通过使用CCurrentSession类,我们现在获得了智能感知支持。如果我们仔细选择属性名称,我们可以在工作时发现属性。这以前是不可能的。
  • 编译器帮助:由于属性可以返回实际的本机对象,编译器通过检查类型是否匹配来帮助我们。例如,当我们将UserID属性用作日期时,编译器会报错。这与之前的情况不同。
  • 跟踪:在会话值更改时添加跟踪信息变得非常简单。以前,如果会话值在许多不同地方发生更改,这将绝非易事。

 

关注点

有关重构的更多信息,请访问:http://www.refactoring.com/

最近,我开始在我的网站上描述我的Web应用程序开发经验:http://www.vaneijkel.com/

 

结论

改进现有Web应用程序可能是一个巨大的挑战,但是如果您做得好,它会变得非常容易和有趣。

请与我分享您的SessionWrapper重构经验。

 

关于Marcel van Eijkel

Marcel van Eijkel自1998年以来一直是一名专业的Microsoft Web应用程序开发人员。此后,他参与了许多Web应用程序重建项目。

 

他对架构、设计模式、重构非常感兴趣。

他最喜欢的技术是DotNet和SQL Server。

 

目前他正在逐一考取微软证书并完成信息技术学士学位。

 

您可以在我的网站上找到我:http://www.vaneijkel.com/

 

历史

2005年8月29日:初始版本。

© . All rights reserved.