论坛首页 Java版 设计模式

对null Object的使用的认识和思考

浏览 3700 次
精华帖 (1) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2008-07-24
本次编码的时候犯了一个愚蠢的错误,在几乎所有的biz和manager层加了一个public static final String NULL = null;以此来作为统一的空对象,而这个完全是多次一举,因为null就可以直接代替,就此看来自己完全没有一点点面向对象的概念。为了防止犯类似的错误,决定查询资料好好讨论一下null Object的使用。

1:返回一个空的域对象而不是null;
在基于领域模型的设计中,在底层定义的domain Object在数据库查询的时候可以返回为空,在此我们先定义一个Do对象。
public class Tree{
private Integer height;
private Integer age;
private String name;
private Double diameter;
//树叶的域对象;
private Leaves leaves;
// get set methods……
}
在DAO层封装和数据库交互的基本方法后,我们在business层开始对业务逻辑进行简单的封装。当我们提供一个findTree的方法的时候,如果在数据库中查询一个年龄为16岁的tree对象为空,一般的情况下我们返回为null对象,这样就会导致程序在要取值的时候必须判断是否为空,实例如下:
public class TreeBiz{
public Tree findTree(Tree tree){
//在这个地方思考一下,如果返回的tree为空的话,下面的方法调用的问题;
// treeDao.findTree(tree)……
}
public String treeName(Tree tree){
return tree.getName();
}
}
如果获取的tree对象为空的话,就会报空指正的错误。所以必须加上if(tree != null)……而这样就会导致程序中过多的判断了空,不够简洁,同时也很容易出错。
如果我们在域对象中重新定义一个空的对象,然后在dao层封装一下,代码的健壮性就会增强了很多。示例如下:
public class Tree{
//增加一个空的tree对象
public static final Tree NULL = new Tree();
private Integer height;
private Integer age;
private String name;
private Double diameter;
//树叶的域对象;
private Leaves leaves;
// get set methods……
}
然后在DAO层封装一下获取tree对象的方法
public class TreeDao{
public Tree findTree(Tree tree){
Tree tree = ……
if(tree == null){
//返回一个空的Tree对象
return Tree.NULL;
}else{
return tree;
}
}
}
这样在业务逻辑层调用TreeDao方法的时候就很不会出现对象空指针的问题,增强了程序的健壮性。
有人或许会问,为什么在为空的时候不直接 new Tree(), 首先:new一个对象需要分配新的内存开销,而static final的NULL对象则在内存中有一块无法改变的存储空间,降低了系统的开销;其次,NULL对象在执行期就被初始化,返回NULL只用指向该内存地址,而不是重新分配地址,提高的性能。
使用NULL Object模式可以确保在DAO层返回有效的对象,及时在查询失败的时候也是如此。这些代表失败的对象“什么也没有做”!
   
最后更新时间:2008-07-24
我觉得该判断空的时候就应该判断空,不该节省的代码就不要随便想当然节省。

为什么要返回一个没有意义的域对象呢?

我宁愿在方法接口注释中注明 某某方法会返回null,返回null表示XXXXX, 也不愿意搞个OOXX的Object再返回去,让上一层的开发人员挠头猜测它的意思。到头来还得钻代码堆里去看怎么实现的。

null的存在是有道理的。这种static final String NULL一类的代码纯属借着代码管理的名义多此一举。至于空域对象, 我还是倾向该null就null~~每个人有每个人的习惯,顺便占个位子看看楼下达人分析

个人愚见。
   
0 请登录后投票
最后更新时间:2008-07-24
null object解决了在你获取域对象中的属性的时候没有判断域对象是否为空的情况下出现 NullPointException的异常的问题。 例如你从域对象A中getx()然后set到域对象B中的时候,可以加强代码的可读性,省略代码中大量的是否为null的判断。

在域对象中设置一个static final对象可以不停的new对象消耗内存,无论是否在DAO层返回一个空的域对象,在领域层设置NULL都有必要的!
   
0 请登录后投票
最后更新时间:2008-07-26
对于“找不到对象”这样的情况自然是返回null比较合适,调用代码的地方至少应该知道该方法是否返回空吧?
避免空指针异常,应该更多的依赖:
1.约定返回集合和数组不能是null,避免调用代码的for循环之外再嵌套一层if。
2.代码写法上常量或者立即数equals变量,而不是变量equals常量。
3.单元测试,协作测试对象返回为null的方法要测试返回null的情况。

第三点做起来会比较复杂,不知道有没有更好的解决办法。
   
1 请登录后投票
最后更新时间:2008-07-24
我个人理解的null object模式主要是用于
1,增强健壮性。
2,减少大量验证null object的重复编码。

即统一规定对象为null时对象对应方法的的默认行为,不过也有限制,就是要求实现公共接口。
具体也是有利有弊,具体问题具体分析。

好像和这里的null object模式不是一个意思吧。。
   
0 请登录后投票
最后更新时间:2008-07-25
rainerWJY 写道
我个人理解的null object模式主要是用于
1,增强健壮性。
2,减少大量验证null object的重复编码。

即统一规定对象为null时对象对应方法的的默认行为,不过也有限制,就是要求实现公共接口。
具体也是有利有弊,具体问题具体分析。

好像和这里的null object模式不是一个意思吧。。


你谈到的这两点在我的帖子中都有提到的。
可以参考Robert C·Martin 的《敏捷软件开发——原则、模式与实践》的第十七章 NULL OBJECT模式
   
0 请登录后投票
最后更新时间:2008-07-25
结果是null就返回null,这样意图明显.一看就知道是什么结果.

反正,类似lz所讲,返回一个空的实体对象,而且这个对象又代表一个null,这很容易弄混淆的,如果前台获取了一个对象,谁也不知道这个究竟是个实实在在的数据库对应的实体对象呢,还是一个不存在的空对象?

至于定义一个NULL,确实多此一举.
   
0 请登录后投票
最后更新时间:2008-07-25
引用
这样在业务逻辑层调用TreeDao方法的时候就很不会出现对象空指针的问题


假定这个叫做Tree的类中有一个类型为SubTree的属性subTree
那么,用了这个null object模式并不能防止
tree.getSubTree()调用出NullPointerException
   
0 请登录后投票
最后更新时间:2008-07-25
foxty 写道
结果是null就返回null,这样意图明显.一看就知道是什么结果.

反正,类似lz所讲,返回一个空的实体对象,而且这个对象又代表一个null,这很容易弄混淆的,如果前台获取了一个对象,谁也不知道这个究竟是个实实在在的数据库对应的实体对象呢,还是一个不存在的空对象?

至于定义一个NULL,确实多此一举.


在一些时候还是必要的,比如一个类或几个类中都有对一个对象的引用
那么就需要在每一个要用到该持有对象的方法中都要做一次判断才能保证程序的健壮性。

这就很麻烦,如果规定了null object 那么就可以省去多个类中的相似的验证null object的方法,而以一个null object类来代替所有的验证。

增加复杂度,但在有些时候会切实的减少程序的重复编码,增强健壮。
   
0 请登录后投票
最后更新时间:2008-07-25
foxty 写道
结果是null就返回null,这样意图明显.一看就知道是什么结果.

反正,类似lz所讲,返回一个空的实体对象,而且这个对象又代表一个null,这很容易弄混淆的,如果前台获取了一个对象,谁也不知道这个究竟是个实实在在的数据库对应的实体对象呢,还是一个不存在的空对象?

至于定义一个NULL,确实多此一举.



这里说的是否为我上面讨论的定义NULL = null的傻冒式的定义?
   
0 请登录后投票
论坛首页 Java版 设计模式

跳转论坛:
JavaEye推荐