If you have a method where the input parameter might be the output.
Let's say that we have a save method that generates an autogenerated id that the client might be interested to use after the call to save().
Person
- id (autogenerated)
- name
- ... (other fields)
Should you design the method signature like this:
1.
public void save(Person person);
The client call:
personService.save(person);
System.out.println(person.getId());
2.
public Person save(Person person);
The client call:
person = personService.save(person);
System.out.println(person.getId());
We know that in a method call that receives an object the reference to that object is passed so any changes 开发者_开发技巧made to the object will be perceived by others as long as they have the same reference. But in the case of remote calls serialization/deserialization occurs so my object reference is a different reference from the remote service object. So even though changes are made there the client won't notice the difference.
At this time I know that the method is not going to be a remote call so I could design it using the first signature. But what if in the future this changes and needs to be called as a remote call.
So my question is: Should I design my API thinking that the API might be called in the future as a remote call and don't use the object parameter as a way to return a value to the client (2) or should I design my API according to my actual situation which the sevice is not remote (1)?
Thank you
It's OK to do both; have save()
return the new ID and have a getId()
method. Returning a value from a "setter" (a method that changes state) has lots of precedents - the java Collections API does it all the time, eg Map.remove(Object)
returns a boolean
.
Fluent Interface
There's another pattern you might want to consider, the Fluent Interface pattern. With a fluent API, you return the object (ie this
) from every method you would otherwise return void
. This lets the caller "chain up" method calls. With a fluent interface, your code would look like this:
public Person save() {
// do your save stuff
return this;
}
If you want the ID after a save, you'd code this:
save().getId();
Simple! This pattern has been used in lots of existing java code too, notably hibernate as in this java fluent code example
I would recommend using fluent, if nothing else to get the practice using it
Why not do both? Use the second signature, modify person locally, and for the time being, just return a reference to that same person. This way, changing it in the future for whatever needs arise won't change the API, and current users can still use your first approach.
That being said, in general, I am uncomfortable with methods that change their parameters unless that is their sole purpose and they are named and documented to indicate this. From the standpoint of "what is the method doing, and what new information do I get from it," I would probably opt for a signature like:
public ID save(Person);
I would recommend using the first approach since objects are seldom used in isolation. The Person object is usually referenced by other entities such as Employee. If you create a new instance, you're invalidating the whole object graph and believe me, you don't want to mess around with deep copying.
As for the possibility of future RPC's, whatever you'll be using to accomplish this, it will most likely be able to update the ID field after the operation commits.
@CPerkins - Objects are passed by "reference value" to be absolutely correct ;)
精彩评论