基于不要返回null之EmptyFactory的应用详解

有很多书上都提出过一个建议:不要返回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;
        }
    }
}

测试代码如下:

不过这种方法有一个缺陷,对于值类型而言,需要装箱

其根本原因是因为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>对象。

(0)

相关推荐

  • 基于不要返回null之EmptyFactory的应用详解

    有很多书上都提出过一个建议:不要返回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 res

  • 基于MongoDB数据库的数据类型和$type操作符详解

    前面的话 本文将详细介绍MongoDB数据库的数据类型和$type操作符 类型 数字 备注 Double 1 双精度浮点数 - 此类型用于存储浮点值 String 2 字符串 - 这是用于存储数据的最常用的数据类型.MongoDB中的字符串必须为UTF-8 Object 3 对象 - 此数据类型用于嵌入式文档 Array 4 数组 - 此类型用于将数组或列表或多个值存储到一个键中 Binary data 5 二进制数据 - 此数据类型用于存储二进制数据 Undefined 6 已废弃 Objec

  • Java基于享元模式实现五子棋游戏功能实例详解

    本文实例讲述了Java基于享元模式实现五子棋游戏功能.分享给大家供大家参考,具体如下: 一.模式定义 享元模式,以共享的方式高效地支持大量的细粒度对象.通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗.享元的英文是Flyweight,表示特别小的对象,即细粒度对象. 二.模式举例 1. 模式分析 我们借用五子棋游戏来说明这一模式. 2. 享元模式静态类图 3. 代码示例 3.1 创建抽象棋子一AbstractChessman package com.demo.flyweight.obj

  • 基于javascript中的typeof和类型判断(详解)

    typeof ECMAScript 有 5 种原始类型(primitive type),即 Undefined.Null.Boolean.Number 和 String.我们都知道可以使用typeof运算符求得一个变量的类型,但是对引用类型变量却只会返回object,也就是说typeof只能正确识别基本类型值变量. var a = "abc"; console.log(typeof a); // "string" var b = 123; console.log(t

  • 基于使用paramiko执行远程linux主机命令(详解)

    paramiko是python的SSH库,可用来连接远程linux主机,然后执行linux命令或者通过SFTP传输文件. 关于使用paramiko执行远程主机命令可以找到很多参考资料了,本文在此基础上做一些封装,便于扩展与编写脚本. 下面直接给出代码: # coding: utf-8 import paramiko import re from time import sleep # 定义一个类,表示一台远端linux主机 class Linux(object): # 通过IP, 用户名,密码,

  • 基于Bootstrap3表格插件和分页插件实例详解

    首先看下实现效果图,如果觉得还不错,请参考实现代码. 上面数据 下面分页 使用方法 1 导入bootstrap的css <link rel="stylesheet" href="css/v3/bootstrap.min.css"> 2 导入jquery <script src="js/jquery-1.10.1.min.js" type="text/javascript"></script>

  • 基于Django模板中的数字自增(详解)

    Django框架的模板提供了{% for %} 标签来进行循环 例如对集合进行循环是比较简单的 {% for row in v1 %} <div>{{row.name}}</div> {% endfor %} 但是在Django中,并不直接支持形如"int i = 0;i<100;i++" 这样的循环,Django有自己的自增方法 假设v1内有2个元素 1,从1开始正向自增 结果1,2 {% for row in v1 %} <div>{{fo

  • 基于Python对象引用、可变性和垃圾回收详解

    变量不是盒子 在示例所示的交互式控制台中,无法使用"变量是盒子"做解释.图说明了在 Python 中为什么不能使用盒子比喻,而便利贴则指出了变量的正确工作方式. 变量 a 和 b 引用同一个列表,而不是那个列表的副本 >>> a = [1, 2, 3] >>> b = a >>> a.append(4) >>> b [1, 2, 3, 4] 如果把变量想象为盒子,那么无法解释 Python 中的赋值:应该把变量视作

  • 基于Java中throw和throws的区别(详解)

    系统自动抛出的异常 所有系统定义的编译和运行异常都可以由系统自动抛出,称为标准异常,并且 Java 强烈地要求应用程序进行完整的异常处理,给用户友好的提示,或者修正后使程序继续执行. 语句抛出的异常 用户程序自定义的异常和应用程序特定的异常,必须借助于 throws 和 throw 语句来定义抛出异常. throw是语句抛出一个异常. 语法:throw (异常对象); throw e; throws是方法可能抛出异常的声明.(用在声明方法时,表示该方法可能要抛出异常) 语法:[(修饰符)](返回

  • 基于Python函数的作用域规则和闭包(详解)

    作用域规则 命名空间是从名称到对象的映射,Python中主要是通过字典实现的,主要有以下几个命名空间: 内置命名空间,包含一些内置函数和内置异常的名称,在Python解释器启动时创建,一直保存到解释器退出.内置命名实际上存在于一个叫__builtins__的模块中,可以通过globals()['__builtins__'].__dict__查看其中的内置函数和内置异常. 全局命名空间,在读入函数所在的模块时创建,通常情况下,模块命名空间也会一直保存到解释器退出.可以通过内置函数globals()

随机推荐