转自http://www.aqee.net/returning-null/
我总感觉一个方法返回null值有问题。当读了Misko Hevery关于how to think about OO的博客文章后,又让我想起这个问题。
我感觉返回null值是有问题的,它大量的被使用在一个方法有不同的返回类型时。简单的用谷歌搜索一下“returning null”,你就会发现有建议把返回类型做成一个null对象。返回一个Null对象在某些情况下是合适的,但并不适合当你需要向客户端传送两种不同的东西的情形。用Misko重构的一段代码来说明这个问题。他重构的是一段登录代码(我非常喜欢他的过程),这段代码大概是这个样子:
Cookie login(Ldap ldap) {
if ( ldap.auth(user, password) )
return new Cookie(user);
return null;
}
从这段代码,可以看出两种情况(从结构上讲)
- 如果认证通过,客户端会被通知验证成功,生成一个新的Cookie
- 如果认证失败,则通过返回的null值通知客户端
客户端的方法应该是什么样的?
public void authenticateUser(User user) {
Cookie userCookie = user.login(ldap);
if (userCookie == null) {
//notify someone that auth failed
} eles {
//register them as logged in
}
}
我们在两个地方做了相同的事情,只是在语法上有稍微的不同,每个地方,我们都要检查验证是否成功。如果我们使用IoC(反向控制)模式,或“Tell Don’t Ask”模式或“Hollywood原则”,会如何?
Cookie login(Ldap ldap, AuthenticationRegistry authenticationRegistry) {
if ( ldap.auth(user, password) )
authenticationRegistry.authSucceeded(new Cookie(user));
authenticationRegistry.authFailed(user);
}
客户端:
public void authenticateUser(User user) {
user.login(ldap,this);
}
public void authSucceeded(Cookie cookie) {
//register them as logged in
}
public void authFailed(User user) {
//register them as auth failed
}
新代码稍微有点复杂,但我感觉它很清晰,实现的更直接。现在我们的两个实体能够相互通信,我们定义了它们通信的方式。我喜欢Misko的重构,我只是更进了一步。好坏可以再讨论,但我想,如果你遇到了这种需要返回两种情况的方法时,IoC是你应该的选择。
分享到:
相关推荐
- `dirname`命令用于获取路径中除最后一部分外的目录部分,如`dirname /usr/local/share/doc/foo/foo.txt` 返回 `/usr/local/share/doc/foo`。 - 这两个命令常用于处理文件路径,方便提取路径的组件。 这些知识点...
生成被最小化,并且文件名包括哈希值。 您的应用已准备好进行部署! 有关更多信息,请参见关于的部分。 yarn eject 注意:这是单向操作。 eject ,您将无法返回! 如果您对构建工具和配置选择不满意,则可以随时...
如lpReturnedString缓冲区不够大,不能容下全部信息,就返回nSize-1(若lpApplicationName或lpKeyName为NULL,则返回nSize-2)。 注解:如lpKeyName参数为NULL,那么lpReturnedString缓冲区会载入指定小节所有设置...
成功则返回非 NULL 值,失败返回 NULL 并设置 `errno`。 **关闭已打开的目录** ```c #include #include int closedir(DIR *dir); ``` 此函数用于关闭通过 `opendir()` 打开的目录。成功则返回 0,失败返回 -1 ...
- `array_only($array, $keys)`: 提取数组中指定键对应的值并返回新数组。 - `array_except($array, $keys)`: 移除数组中指定键对应的值并返回新数组。 2. **字符串助手**: - `str_slug($string, $separator)`:...
4. 序列(Sequence)在Oracle中用于生成唯一的整数,`CURRVAL`返回序列当前值,`NEXTVAL`递增并返回新值 5. SQL别名(Alias)可以使用`AS`关键字创建,例如`SELECT ename, sal*12 AS "Annual Salary" FROM emp` 6....
HANDLE hFile = CreateFile("your_file_path", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { FILETIME creationTime, ...
4. 主关键字:主关键字是表中的唯一标识符,不允许有NULL值和重复值。选项B错误,因为主关键字字段不应包含NULL值。 5. 数据结构:栈遵循“先进后出”(LIFO)原则,因此选项B正确。循环队列、队列和二叉树都有不同...
char *envp[] = {"PATH=/mnt/hgfs/share", NULL}; execle("/bin/ls", "ls", "-l", NULL, envp); ``` - **`int execv(const char *path, char *const argv[]):`** 与`execl`类似,但参数传递方式略有不同。 ...
- 锁包括共享锁(Share Locks)和独占锁(Exclusive Locks)等。 3. **索引(Indexes)**: - 索引可以加速查询的速度。 - 包括聚集索引(Clustered Indexes)和非聚集索引(Nonclustered Indexes)。 4. **...
- 如果成功读取文件,则返回非零值;否则返回零。 #### 五、程序流程 1. **打开文件**: - 使用`CreateFile`函数尝试打开文件`"c:\\mianhou.txt"`。 - 成功打开后输出“文件打开成功!”的信息,否则输出“文件...
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); ``` 3. **设置字体颜色**:使用`...
调用完成后,`hResult`将包含函数返回的值。 除了直接调用API函数,还需要处理错误。大多数Win32 API函数在失败时会返回一个错误代码,例如`NULL`或`FALSE`。你应该检查这些返回值,并根据需要进行错误处理。例如:...
- **Null (1)**:无效值。 - **Row-S(SS) (2)**:共享行锁。 - **Row-X(SX) (3)**:排他行锁。 - **Share (4)**:共享对象锁。 - **S/Row-X(SSX) (5)**:共享加排他行锁。 - **Exclusive (6)**:排他对象锁。 ...
HANDLE hFile = CreateFile("C:\\example.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ``` 如果成功,`hFile`将包含有效的句柄;否则,它将为`INVALID_HANDLE_...
`CreateFile`函数是Windows API中的一个重要功能,主要用于创建或打开各种类型的文件和设备对象,并返回一个句柄,该句柄可用于后续对这些对象的操作。此函数可以用于操作多种类型的对象,包括但不限于文件、管道、...
当 ftok 函数执行成功时,一个 key_t 值将被返回,否则返回 -1。 ftok 函数的作用是将文件的索引节点号取出,前面加上子序号得到 key_t 的返回值。例如,如果文件的索引节点号为 65538,换算成 16 进制为 0x010002...
根据提供的文件信息,可以看出这是一份关于Oracle数据库常见问题解答的手册或文档的一部分。文档包含了多个与Oracle数据库管理和操作相关的具体问题及解答示例。接下来,我们将对文档中提到的关键知识点进行详细的...
1. **函数定义**:`IsNumeric` 方法接收一个字符串 `str` 作为参数,并返回一个布尔值表示该字符串是否仅由数字组成。 2. **空检查**:首先检查传入的字符串是否为空或长度为零,如果是,则直接返回 `false`。 3. **...
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); ``` 2. **构建命令数据包**:接着定义自定义命令的结构体,填充必要的字段,如命令类型、值、方向等。 ```c VENDOR_OR_CLASS_REQUEST_CONTROL ...