[你必须知道的.NET]第二十一回:认识全面的null
[2] [你必须知道的.NET]第二十一回:认识全面的null
[3] [你必须知道的.NET]第二十一回:认识全面的null
[4] [你必须知道的.NET]第二十一回:认识全面的null
[5] [你必须知道的.NET]第二十一回:认识全面的null
系列文章导航:
[你必须知道的.NET] 第四回:后来居上:class和struct
[你必须知道的.NET] 第五回:深入浅出关键字---把new说透
[你必须知道的.NET] 第六回:深入浅出关键字---base和this
[你必须知道的.NET] 第七回:品味类型---从通用类型系统开始
[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
[你必须知道的.NET] 第十回:品味类型---值类型与引用类型(下)-应用征途
[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)
[你必须知道的.NET] 第十二回:参数之惑---传递的艺术(下)
[你必须知道的.NET] 第十三回:从Hello, world开始认识IL
[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在
[你必须知道的.NET] 第十六回:深入浅出关键字---using全接触
[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考
[你必须知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二
4 Nulll Object模式
模式之于设计,正如秘笈之于功夫。正如我们前文所述,null在程序设计中具有举足轻重的作用,因此如何更优雅的处理“对象为空”这一普遍问题,大师们提出了Null Object Pattern概念,也就是我们常说的Null Object模式。例如Bob大叔在《敏捷软件开发--原则、模式、实践》一书,Martin Fowler在《Refactoring: Improving the Design of Existing Code》一书,都曾就Null Object模式展开详细的讨论,可见23中模式之外还是有很多设计精髓,可能称为模式有碍经典。但是仍然值得我们挖据、探索和发现。
下面就趁热打铁,在null认识的基础上,对null object模式进行一点探讨,研究null object解决的问题,并提出通用的null object应用方式。
解决什么问题?
简单来说,null object模式就是为对象提供一个指定的类型,来代替对象为空的情况。说白了就是解决对象为空的情况,提供对象“什么也不做”的行为,这种方式看似无聊,但却是很聪明的解决之道。举例来说,一个User类型对象user需要在系统中进行操作,那么典型的操作方式是:
if (user != null)
{
manager.SendMessage(user);
}
这种类似的操作,会遍布于你的系统代码,无数的if判断让优雅远离了你的代码,如果大意忘记null判断,那么只有无情的异常伺候了。于是,Null object模式就应运而生了,对User类实现相同功能的NullUser类型,就可以有效的避免繁琐的if和不必要的失误:
// Copyright : www.anytao.com
// Author : Anytao,http://www.anytao.com
// Release : 2008/07/31 1.0
public class NullUser : IUser
{
public void Login()
{
//不做任何处理
}
public void GetInfo() { }
public bool IsNull
{
get { return true; }
}
}
IsNull属性用于提供统一判定null方式,如果对象为NullUser实例,那么IsNull一定是true的。
那么,二者的差别体现在哪儿呢?其实主要的思路就是将null value转换为null object,把对user == null这样的判断,转换为user.IsNull虽然只有一字之差,但是本质上是完全两回事儿。通过null object模式,可以确保返回有效的对象,而不是没有任何意义的null值。同时,“在执行方法时返回null object而不是null值,可以避免NullReferenceExecption异常的发生。”,这是来自Scott Dorman的声音。
通用的null object方案
下面,我们实现一种较为通用的null object模式方案,并将其实现为具有.NET特色的null object,所以我们采取实现.NET中INullable接口的方式来实现,INullable接口是一个包括了IsNull属性的接口,其定义为:
public interface INullable
{
// Properties
bool IsNull { get; }
}
仍然以User类为例,实现的方案可以表达为:
图中仅仅列举了简单的几个方法或属性,旨在达到说明思路的目的,其中User的定义为:
// Copyright : www.anytao.com
// Author : Anytao,http://www.anytao.com
// Release : 2008/07/31 1.0
public class User : IUser
{
public void Login()
{
Console.WriteLine("User Login now.");
}
public void GetInfo()
{
Console.WriteLine("User Logout now.");
}
public bool IsNull
{
get { return false; }
}
}
而对应的NullUser,其定义为:
// Copyright : www.anytao.com
// Author : Anytao,http://www.anytao.com
// Release : 2008/07/31 1.0
public class NullUser : IUser
{
public void Login()
{
//不做任何处理
}
public void GetInfo() { }
public bool IsNull
{
get { return true; }
}
}
同时通过UserManager类来完成对User的操作和管理,你很容易思考通过关联方式,将IUser作为UserManger的属性来实现,基于对null object的引入,实现的方式可以为:
// Copyright : www.anytao.com
// Author : Anytao,http://www.anytao.com
// Release : 2008/07/31 1.0
class UserManager
{
private IUser user = new User();
public IUser User
{
get { return user; }
set
{
user = value ?? new NullUser();
}
}
}
当然有效的测试是必要的:
public static void Main()
{
UserManager manager = new UserManager();
//强制为null
manager.User = null;
//执行正常
manager.User.Login();
if (manager.User.IsNull)
{
Console.WriteLine("用户不存在,请检查。");
}
}