如果不存在,那么在get中创建某些东西是不好的编码习惯吗?


18

因此,我有一个Web服务,该服务具有类似的功能getAccount,如果有该服务,它将在帐户中返回标识符,否则将引发异常。如果抛出的异常与获取信息相同,则客户端将始终希望创建一个帐户。

我正在为客户端创建一个便利库,该客户端将处理内部的所有webservice调用,因此他们不需要知道如何自己进行调用。

我想知道的是,如果我要创建一个getAccount(accountName)可以在帐户存在时获取该帐户的帐户,如果不创建该帐户并返回信息,那是一件不好的事情吗?我应该将其留给客户端来处理异常还是将其命名为诸如getOrCreateAccount之类的东西?有关系吗?

在get操作中创建内容是不好的做法吗?


9
至少,我会命名getOrCreateAccount或类似名称。
Telastyn 2012年

4
在延迟初始化的上下文中,这似乎是有效的。但是,这取决于您是否需要在库中使用该模式。
克里斯·C

1
我喜欢动词acquire,喜欢acquireAccount。在我遇到的任何主要协议中,它都没有现成的含义,它具有非常适合它的命令环。“做任何你需要做的事情来为我获取其中之一。索要,建造,伪造,窃取它,我不在乎,只要让我一个就可以死。”
丹·罗斯

2
“客户总是希望创建一个帐户”-看起来非常不寻常。如果由于用户键入错误的用户名而无法获得该帐户,那么我当然不想创建使用错误键入的名称的帐户。
gnasher729

根据javabean规范,oracle.com / technetwork / articles / javaee / spec- 136004.htmlgetSomething()适用于getter和setSomething()setter。伊莫事情,做一些更智慧必须调用别的东西,即fetchSomethingobtainSomethingcomputeSomething,或doSomethingElse
ccpizza

Answers:


31

是的,这很重要。在我看来,在没有被记录为具有创造能力的过程中创建某些东西通常是一种不好的做法。命名该过程getOrCreate...或使用一个单独的create...过程,然后,如果您确实需要,getOrCreate...请先尝试执行一次get...,如果失败,则调用create...,然后再调用get...

get...如果get操作失败,库的用户可能不会期望该过程创建。如果他们突然发现测试调用get...创建了整吨的数据,他们可能会感到很惊讶。以及他们如何清理它?如果他们编写代码以为如果get...失败就会出错并想以自己的方式处理该怎么办?


谢谢,创建实际上返回了get也会返回的id,所以我不必get... create... get...只做前两个。我将与客户谈谈他们是否会需要仅调用a get而又不想创建的功能
Mike

6
@迈克:我仍然认为它应该有它create的名字,只是为了100%清楚正在发生的事情。
FrustratedWithFormsDesigner 2012年

是的,我同意,我正计划按照getOrCreate的方式制作它,因为我最初的想法只是要实现,但我意识到尚不清楚它是否还在后台创建东西
Mike

1
这太晚了,但是getOrCreate在流行的Web框架中优先: docs.djangoproject.com/en/1.10/ref/models/querysets/…–
tex

18

不,这不是“坏习惯”。只要您和其他开发人员都同意,那就是您希望它如何工作,那就好了。毕竟,它将要返回一个帐户,这就是您想要的。帐户是在“幕后”创建的,与呼叫者无关。


10
唯一的例外是它是公开可用的API。更大的社区已经同意GET是独立的和无效的。换句话说,每次都执行相同的操作,这是一种不更改服务器状态的安全方法。这在REST Wiki中。除此之外,如果API仅存在于您自己的小世界中,请执行您的小组接受的所有事情。
jmort253

9
我不同意,即使对于公共API来说也很好-只要在API应该执行的操作范围内有意义。如果只有一个可以完成上述任务,那么在API中创建多个条目毫无意义。
GrandmasterB 2012年

作为记录,它是一个完全内部的库,我可以告诉使用它的团队如何工作
Mike

1
@ jmort253:如果服务没有对客户端可见的副作用,则该服务无效。服务器可以随心所欲。
凯文·克莱恩

1
@kevincline,我想我是在考虑用我的信用卡充值的。如果服务器根据GET请求向我的卡收费,但每次运行时仍给我类似“拒绝”的结果,那似乎与GET的精神背道而驰。话虽如此,我确实明白你的意思。服务器可以计算GET请求的数量,并在3次查询后将我锁定,从而限制了我的访问速度,但无需更改我的帐户的任何详细信息。当有人说服务器状态未修改时,我确实认为这是一个重要的区别。也许我应该改为说“服务器上的客户端状态”
jmort253

10

如果getAccount()可以始终返回一个帐户,那么从调用者的角度来看,该帐户确实存在,并且一直存在。无需getAccount()“创建”任何东西。该帐户不必存储在任何地方,除非它与默认帐户不同。


+1通常GetOrCreate是错误的语义,但是获取无论其是否物理存在都可能“逻辑上”存在的对象是可以的。例如,一个稀疏的可变项数组可能没有为元素1,841,533分配任何存储,但是仍然可以通过创建一个新对象,将其存储并返回引用来“检索”该元素。
2014年

4

创建3种方法最有意义:

getAccount->仅获取帐户。

createAccount->创建一个帐户。

getAccountAndCreateIfNeeded->选择您自己的命名;)

为什么分离:您有一种获取和创建的简单方法。对于这两者来说,这都是一种明确的可测试方法。对于getAccount它不是一个例外,没有找到该帐户。因此,只需返回false或类似的值即可。

然后,您可以在分组函数中使用该返回值:getAccountAndCreateIfNeeded(现在也可以测试),它应该始终返回一个帐户。无论你问什么。

所有这三种方法都很清楚,它们的作用和返回的作用也很清楚。您现在可以与您的团队达成协议,但是从长远来看,这种例外非常可怕。只需将它们弄清楚,就不会有任何问题。


另外,从“清除代码”开始:“如果您的方法无法执行其名称所暗示的操作,则抛出异常。” 我将在'GetOrCreateIfneneeded'中有一个Try / Catch块,该块抛出失败的GET,然后在Throw中包含'createAccount',以获取失败的get返回的任何异常类型。
格雷厄姆

我可能会建议第四个方法:getAccountIfExists,它可以获取一个帐户或表明不创建新帐户就不存在。该getAccount方法本身应以该帐户存在为前提,如果不存在则抛出异常。
supercat 2014年

2

这要视情况而定。

例如,您可以使用它来进行延迟加载/实例化,将数据加载或实例创建推迟到实际需要时才进行。这通常是明智的做法,因为它可以节省您可能不需要的资源(如果不再需要类/数据,则永远不会加载它)。

但是,在这种特殊情况下,我想说有一个名为getAccount的方法(如果不存在则可以创建一个新帐户)不是一个好习惯。如果用户已经提供了一些凭据来标识一个特定帐户,但找不到该帐户,这是否意味着该用户还不是客户,应该为其创建了一个帐户,或者这意味着凭据输入错误?并且需要询问用户以确认他们已经输入了要输入的内容?

如果您有一个getAccount方法可以在无法识别新帐户的情况下创建一个新帐户,那么您别无选择。如果将帐户创建和帐户退出划分为不同的方法,则在尝试尝试获取帐户失败时可以灵活决定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.