小心你的全局变量!--“悬挂式全局”设计方式小议

很多时候(似乎昨天还有人在QQ上问Delphi怎么定义全局变量…),很多人都喜欢用全局变量来保存一些数据, 这样可以随时随地的调用他们。这样看似方便(实际上也很方便),但这个时候你却为自己埋下了很深的隐患。

全局,顾名思义就是在任何地方都可以访问到的,也是任何机制都可以修改或显示的(当然你可以对它加一些限制,但这些限制终归也是全局的),那么这个时候,它就成了一个不可控量。所谓不可控量简单的说就是一个量的的状态未知。

OOP设计中是坚决杜绝不可控量的存在的,因为不可控量的存在会破坏数据的封装性以及可维护性。

我们都有过这种体验:一个全局字段被设计出来,任何时候它都会被更改,但随着时间的推移,我们不得不使用越来越多的记忆细胞来记忆到底那里用到了它,而在设计是还要考虑对它的修改会影响到哪里的调用。往往这个时候是让人最抓狂的时候。最常见的情况就是我们在ASP/ASP.NET中使用的Session变量,很多人都会直接操作Session变量,并通过特征字符串来访问它,这就给这个程序带来了很大的不可控性。

另一种情形:一个操作需要一个生命周期很长的变量来进行,于是你在上面提到的建议下把它设计成了类,嗯,这是很好的开始,至少对于这个变量来说可能是可控的了,但是考虑到变量的生命周期,你把它设计成了静态类,呜,似乎问题被圆满解决了,全局和生命周期都兼顾了。可是接下来问题又来了,随着设计的往下进行,你发现原先设计的静态类需要修改,还有若干类似功能的类也要写出来,那么这个时候,你想到了继承…于是…你得到了编译器的友情提示:静态类不能被继承…这个时候,键盘会变成什么形状我们不得而知

上述两种情况在很多初学者甚至有丰富经验的人中出现频率很高,这在OOP的思想里是无法被接受的。

针对上述两种情况,一个被暂时称为“悬挂式全局”的设计方式可以比较好的解决。

所谓的悬挂式,是说把一个全局的逻辑或者数据“委托”给一个可控的量来管理。比如对于这样一个设计:

用户登录验证是我们最常用的功能模块,这个模块的设计一般是结合Session变量来设计的。首先我们会在登录的时候将数据存入Session,在使用的时候又读取Session中的数据,但是考虑到上述的问题,我们并不直接使用它。

在这里,我们设计两个类:

TRoleData,TRoleSession

其中TRoleData封装了与用户有关的所有的数据及其操作,TRoleSession则只是实现了对TRoleData的封装以及对一个特有Session变量的维护,如下代码:

 

public class TRoleSession: System.Web.UI.Page
 
{
  
const string ROLE_KEY="SESSION_ROLE_KEY";
  
public void abandon()
  
{
   Session[ROLE_KEY] 
= null;
  }

  
public TUserInfo LoginUser
  
{
   
get
   
{
    
return ((TRoleData)(Session[ROLE_KEY]));
   }

  }


  
public void login( string userid, string password )
  
{
   
//————-
   
//登录验证代码
   
//————-
   Session[ROLE_KEY] = xxx;
  }

  
public bool hasLogin 
{
   
get {
    
return Session[ROLE_KEY] != null;
   }

  }

 }

 

上述的ROLE_KEY可以使用MD5或者GUID来生成此对象的唯一标识符,以避免其他的地方可能会通过标识字段修改Session的值,TRoleSessionl将危险的Session变量隐藏起来,只向外界提供必需的数据接口,这样TRoleData就只能通过TRoleSession来访问和控制了,最大程度的避免了全局变量带来的程序不可控性,另外TRoleData可以自由扩展,这个数据对象就像悬挂在了Session上。

一般来说,在MVC式设计方式当中,Model和View的没有实体逻辑及业务操作,它们不可以被有效的控制,所以是无法作为全局变量出现的,只有Control才能够凭借自身的可控性来管理上述两种数据的状态。那么由OOP原则来看,将Control也就是控制逻辑元素来作为全局是最理想的,“悬挂式全局”设计方式正是利用了这一点。

标签:
文章分类 FK Coding, 一张窗户纸
1 条评论在 “小心你的全局变量!--“悬挂式全局”设计方式小议” 上
  1. 鼠标 说道:

    这种悬挂式全局有一个原则:
    <br> 常量必须仅仅跟该类紧密耦合,适用于表示该类的状态。
    <br> 而很多时候,常量还有别的用途,比如表示流程状态,一个继承体系的共享状态,此时这些常量需要导出,也就是全局的常量。
    <br> 那么建议导出到一个不会被实例化的类中。
    <br> 另外一个建议就是如非必要不要使用字符串,使用2进制数字,这样我们的状态可以叠加。

鼠标 进行回复 取消回复

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

点赞
如果您觉得很赞,我将非常乐意接受虚拟币的捐赠,以示您对我的肯定。

比特币钱包地址:
1PqpqA8FyH3NbfCrbcRd1YxQk3LEsSEYDV
莱特币钱包地址:
LRTdmovGGVEHCKWz7JdL9aiB7VZkuNycJf
站点勋章
网站统计