Passing Parameters as Maps: Good or Bad?

I have been thinking about whether passing parameters as a Map of objects is a good idea or not when one is simply using POJOs. Of course, I am only talking about doing this in a few select cases. An example is an online service that keeps track of its users in a database. Think about the differences of the sample code:

// sample code using a Map

class UserManager

{

..

publicvoid userTriedRegistering(Map<String, String> paramaterMap)

{

String username = parameterMap.get("username");

String password = parameterMap.get("password");

String email = parameterMap.get("email");

...

// add user to database

}

}

// sample code not using Properties

class UserManager

{

...

publicvoid userTriedRegistering(String username, String password, String email)

{

...

// add user to database

}

}

My point in posting this code is to show the advantages and disadvantages of both methods of passing parameters. In both examples, UserManager has the same amount of dependencies -- in the former example, the dependencies just happen to be the keys in a Map. So what is the advantage of passing parameters in a Map? Well, let's say you were to swap the implementation of the former code example, and in doing so you had to add on a "nickname" field for the User's nickname on the server. You would be changing the number of parameters, which will affect the client classes of the latter example but not those of the the former. The only disadvantage that I can think of in using the Map is that it adds new complexities.

I was just wondering about your thoughts on whether it was a good idea to do this in select cases, such as the code example shown above, and what you think the range of scenarios that this idea applies to is. I think it is best to do so when the number of parameters are very likely to change when the code is reused.

[2605 byte] By [ktm5124a] at [2007-10-2 19:30:57]
# 1
Why not public void userTriedRegistering(UserRegInfo info) {String userName = info.getUserName();// etc.} ?
jverda at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 2

> I have been thinking about whether passing parameters

> as a Map of objects is a good idea or not when one is

> simply using POJOs. Of course, I am only talking

> about doing this in a few select cases. An example is

> an online service that keeps track of its users in a

> database. Think about the differences of the sample

> code:

I'd rather have the parameters explicitly spelled out, especially in this particular case.

> My point in posting this code is to show the

> advantages and disadvantages of both methods of

> passing parameters. In both examples, UserManager has

> the same amount of dependencies -- in the former

> example, the dependencies just happen to be the keys

> in a Map. So what is the advantage of passing

> parameters in a Map? Well, let's say you were to swap

> the implementation of the former code example, and in

> doing so you had to add on a "nickname" field for the

> User's nickname on the server. You would be changing

> the number of parameters, which will affect the

> client classes of the latter example but not those of

> the the former. The only disadvantage that I can

> think of in using the Map is that it adds new

> complexities.

>

I think the biggest reason not to is a poorly defined interface and contract.

> I was just wondering about your thoughts on whether

> it was a good idea to do this in select cases, such

> as the code example shown above, and what you think

> the range of scenarios that this idea applies to is.

> I think it is best to do so when the number of

> parameters are very likely to change when the code is

> reused.

I never like seeing interfaces designed this way. Too generic. It doesn't give the client or the POJO a clear idea of what's required or what's coming. How do you validate a Map?

%

duffymoa at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 3

> Why not > public void userTriedRegistering(UserRegInfo info) {

>String userName = info.getUserName();

> // etc.

> }

> ?

The advantage of that is that it makes more sense; the disadvantage is that it reveals implementation details. It is more generic than spelling out the parameters, but less generic than a map. However, perhaps it is best to compromise.

Oh, and there is the possibility that I am being a "small boy with pattern syndrome." =)

ktm5124a at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 4

The table in a database is nothing more than a set of records (objects). That is, the phrase "a table keeps records" translated to java sounds as "a set keeps objects". The entities stored are nothing more than a collection of fields.

When you work in java you do it like:

Set users<User> = new SqlTable<User>();

users.add(user);

u = users.get(key_name);

Why do you think you need to break the object into the fields when the implementation of the set is a persistent storage? You may need to do that behind the scenes. However, making use of reflection; that is, treating user as a bean, we can make the following container:

class SqlTable<E> implements Set<E> {

SqlTable(E, connection) {

//parse and extract the bean fields

// might create a table if not exists

}

void add(E o) {

// scan the bean values composing the SQL 'insert' request

// execute SQL

}

void remove(E key) {

// exetute another SQL request

}

}

In addition to having the entities, you might create a corresponding key-object for every bean. These keys should consist exclusively of the key-fields and match with the beans on equals() and getHash() methods. You may derive the beans (sets of fields) by extending the keys.

This approach should give a generic java Collections interface to any persistent tables. The bonus of compatibility is that you can easily switch between the storages. Unfortunately, this natural solution is cluded by the lack of get(key) method in the Set interface.

valjoka at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 5

The obvious solution to this problem is to use a data structure that actually has a key: Map.

The mapping (no pun intended) from Map to relational tables, however, is not 1:1:

(1) Relational tables may have several candidate keys in addition to the primary key. For example, a Person table might have a surrogate primary key, but clients of that table are likely to want to search using other criteria (last name, tax ID, etc.) These will translate into several finder methods. Map only has one key.

(2) There's no notion of parent:child 1:m or m:n relationships built in. This simple view only works when the object model maps one per table.

(3) Taking advantage of polymorphism isn't easy.

The better approach is to use the DAO pattern and implement it using O/R tools like Hibernate.

I'd also prefer using Spring to handle connections rather than having them in code. Spring manges them better, and declarative transactions are a beautiful thing.

But this is specific to the problem of developing a persistence layer. The question is more generic: Is it good or bad to pass Maps? I'm still voting "no".

%

duffymoa at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 6
wouldn't that leave far too much room for duff data to be passed? presumably you're looking to keep method signatures tidy? I use the solution jverd suggested all the time for this, a Params class
georgemca at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 7

> The only disadvantage that I can

> think of in using the Map is that it adds new

> complexities.

>

You are trading compile time checks with run time checks.

There are no real advantages to the map solution except that you have to type less code. The solution to that is to use code generation.

> I was just wondering about your thoughts on whether

> it was a good idea to do this in select cases, such

> as the code example shown above, and what you think

> the range of scenarios that this idea applies to is.

> I think it is best to do so when the number of

> parameters are very likely to change when the code is

> reused.

Reused or modified? Those are significantly different.

As far as signature changes when the code changes then use a DTO pattern to pass in the actual data.

jschella at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 8

> > Why not > > public void userTriedRegistering(UserRegInfo info)

> {

> >String userName = info.getUserName();

> > // etc.

> > }

> > ?

>

> The advantage of that is that it makes more sense;

> the disadvantage is that it reveals implementation

> details. It is more generic than spelling out the

> parameters, but less generic than a map. However,

> perhaps it is best to compromise.

>

> Oh, and there is the possibility that I am being a

> "small boy with pattern syndrome." =)

Yep. What jverd did is completely correct. It is not more generic than spelling out the parameters, its exactly the same level.

I often use a map when i want to get something done quickly, then I come back and start creating more concrete classes where I think they are required.

_dnoyeBa at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 9

> > Why not > > public void userTriedRegistering(UserRegInfo info)

> {

> >String userName = info.getUserName();

> > // etc.

> > }

> > ?

>

> The advantage of that is that it makes more sense;

> the disadvantage is that it reveals implementation

> details. It is more generic than spelling out the

> parameters, but less generic than a map. However,

> perhaps it is best to compromise.

>

> Oh, and there is the possibility that I am being a

> "small boy with pattern syndrome." =)

What makes you think that reveals implementation details where your Map solution does not?

kablaira at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 10

The map approach sucks! (Sorry to lower the tone, but I feel it needed to be said).

If you're worried about changing method signature don't be - right click, refactor, change method signature, add parameter. You should be more worried about writing clean, readable code.

Individual paramters or the UserRegInfo are the way to go. You don't run the risk of breaking your code by mispelling one of the keys. It won't take much longer - you can get your IDE to generate it for you.

The exception to this is where you have things like the JMS / JNDI standards with multivendor implementations. In that case a map / properties object is not such a bad idea as it allows you to pass in vendor specific details if necessary without giving up too much portability.

SteveNaivea at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 11

Java's not well suited to this style of programming. There other options, however...

(defun register (&rest params)

(destructuring-bind (&key username password email) params

(list username password email)))

(register :username "joeblow" :password "pass" :email "joeblow@email.com")

->

("joeblow" "pass" "joeblow@email.com")

RadcliffePikea at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...
# 12
Is that Lisp? It's so long since I've written any I can barely remember!
SteveNaivea at 2007-7-13 21:18:15 > top of Java-index,Other Topics,Patterns & OO Design...