基于不要返回null之EmptyFactory的应用详解
程序员文章站
2023-12-19 20:38:34
有很多书上都提出过一个建议:不要返回null对象。比如下面的getusers方法:public class user{ public s...
有很多书上都提出过一个建议:不要返回null对象。
比如下面的getusers方法:
public class user
{
public string id { get; set; }
public string name { get; set; }
}
public list<user> getusers()
{
list<user> result = new list<user>();
// search db for user
return result;
}
如果其他方法由getusersofxxx,getusersbyxxx之类的方法,那么就有大量
list<user> result = new list<user>();
考虑到这一点,可以将new list<user>() 封装到方法中,这就是”工厂”模式了.
因为可能不是list<user> ,也许是stack<user> 更或者是observablecollection<user>
所以配合泛型,代码如下:
public static class emptyfactory
{
public static t empty<t>() where t : ienumerable, new()
{
return new t();
}
}
使用如下:
list<string> emptylist = new list<string>();
stack<string> emptystack = new stack<string>();
observablecollection<string> emptyobserable = new observablecollection<string>();
emptylist = emptyfactory.empty<list<string>>();
emptystack = emptyfactory.empty<stack<string>>();
emptyobserable = emptyfactory.empty<observablecollection<string>>();
虽然这样写可以满足要求,但是可以发现基本没什么好处,写emptyfactory还不如new 来得快。
不过如果能够缓存对象的话,也许emptyfactory有作用。
考虑到这一点,为emptyfactory增加缓存机制的代码如下,使用dictionary<type,object> 来实现
public static class emptyfactory
{
private static dictionary<type, object> cacheemptyobjects =
new dictionary<type, object>();
public static t empty<t>() where t : ienumerable, new()
{
type generictype = typeof(t);
if (cacheemptyobjects.containskey(generictype))
{
return (t)cacheemptyobjects[generictype];
}
else
{
t tempemptyobject = new t();
cacheemptyobjects.add(generictype, tempemptyobject);
return tempemptyobject;
}
}
}
测试代码如下:
public static class emptyfactory<t> where t : ienumerable, new()
{
private static dictionary<type, t> cacheemptyobjects = new dictionary<type, t>();
public static t empty()
{
type generictype = typeof(t);
if (cacheemptyobjects.containskey(generictype))
{
return cacheemptyobjects[generictype];
}
else
{
t tempemptyobject = new t();
cacheemptyobjects.add(generictype, tempemptyobject);
return tempemptyobject;
}
}
}
使用的时候,只需要
比如下面的getusers方法:
public class user
{
public string id { get; set; }
public string name { get; set; }
}
public list<user> getusers()
{
list<user> result = new list<user>();
// search db for user
return result;
}
如果其他方法由getusersofxxx,getusersbyxxx之类的方法,那么就有大量
list<user> result = new list<user>();
考虑到这一点,可以将new list<user>() 封装到方法中,这就是”工厂”模式了.
因为可能不是list<user> ,也许是stack<user> 更或者是observablecollection<user>
所以配合泛型,代码如下:
public static class emptyfactory
{
public static t empty<t>() where t : ienumerable, new()
{
return new t();
}
}
使用如下:
list<string> emptylist = new list<string>();
stack<string> emptystack = new stack<string>();
observablecollection<string> emptyobserable = new observablecollection<string>();
emptylist = emptyfactory.empty<list<string>>();
emptystack = emptyfactory.empty<stack<string>>();
emptyobserable = emptyfactory.empty<observablecollection<string>>();
虽然这样写可以满足要求,但是可以发现基本没什么好处,写emptyfactory还不如new 来得快。
不过如果能够缓存对象的话,也许emptyfactory有作用。
考虑到这一点,为emptyfactory增加缓存机制的代码如下,使用dictionary<type,object> 来实现
复制代码 代码如下:
public static class emptyfactory
{
private static dictionary<type, object> cacheemptyobjects =
new dictionary<type, object>();
public static t empty<t>() where t : ienumerable, new()
{
type generictype = typeof(t);
if (cacheemptyobjects.containskey(generictype))
{
return (t)cacheemptyobjects[generictype];
}
else
{
t tempemptyobject = new t();
cacheemptyobjects.add(generictype, tempemptyobject);
return tempemptyobject;
}
}
}
测试代码如下:
不过这种方法有一个缺陷,对于值类型而言,需要装箱。
其根本原因是因为emptyfactory不知道t是什么,如果emptyfactory知道t的话,那么就可以使用dictionary<t,t> 的缓存了。
解决这个问题的思路是将emptyfactory变成泛型类:
代码如下:
复制代码 代码如下:
public static class emptyfactory<t> where t : ienumerable, new()
{
private static dictionary<type, t> cacheemptyobjects = new dictionary<type, t>();
public static t empty()
{
type generictype = typeof(t);
if (cacheemptyobjects.containskey(generictype))
{
return cacheemptyobjects[generictype];
}
else
{
t tempemptyobject = new t();
cacheemptyobjects.add(generictype, tempemptyobject);
return tempemptyobject;
}
}
}
使用的时候,只需要
当然也可以emptyfactory<list<user>>.empty();
为什么不用enumersble.empty<t>方法呢?
因为enumerable.empty<t> 返回的是ienumerable<t>对象。