Reputation: 9788
Im curious, in JavaScript is effective way to write a function constructor using options object which helps instance creation since you don't have to remember what variable goes to what spot and the reader can see without going inside the declaration what these values means and don't need to care about order of provided parameters.
Example:
var Dog = function(options) {
this.name = options.name;
this.age = options.age;
this.weight = options.weight;
};
// This is the part I'am interested in
var dog = new Dog({
name: "luffy",
age: 7,
weight: 23
});
The question is, what is the closest code which could mimic this functionality in Java, or is there any? If not, why not?
To clarify:
I'am interested in visibility aspects of JavaScript notation and that I don't need to care about order or provided values, using Java format:
new Dog("luffy", 7);
won't tell me what is i.e. 7
and it requires me to provide values in specified order for the class.
Upvotes: 2
Views: 113
Reputation: 565
Use Java Map Object ;)
Map<String, Object> params = new HashMap<String, Object>>(){{
put("name", "luffy");
put("age", 7);
put("weight", 23);
}};
Dog dog = new Dog(params);
Upvotes: 1
Reputation: 1075755
Updated
I originally misread this answer, which describes the idiom for this from Effective Java 2nd Edition. I thought it didn't do something it does do, and so this answer is really just a duplicate of that answer (except that that answer's syntax was better). I've marked this answer as a CW.
I'm leaving this intact, though, since it was apparently of some use to the OP. But I'm posting the other answer's syntax below.
The solution from Effective Java 2nd Edition is to have the constructor accept an "options" object using the builder pattern (Foo.Options
below). This is so the real object is either fully-constructed or not constructed, but never half-constructed; the Foo.Options
instance may be half-constructed, but we don't care as it's just an options class. This also lets us put the logic around duplicated options or missing options in a nice separate (but contained) class.
Here's what it looks like to use: (but note that the Effective Java syntax is even simpler, see below)
Foo f = new Foo((new Foo.Options()).first("primero").second("secondo"));
(Foo
could also provide a positional-arguments constructor if desired, as an option, for callers who wanted to use that; see note after the big code block.)
Here's what Foo
(and Foo.Options
) look like:
public class Foo {
public Foo(Foo.Options opts) {
if (!opts.isValid()) {
// Throw exception
}
// Use options
}
public static class Options {
private String _first = null;
private String _second = null;
public Options() {
}
public Options(String f, String s) {
this.first(f).second(s);
}
public boolean isValid() {
return this._first != null && this._second != null;
}
public Options first(String f) {
this._first = f;
return this;
}
public String getFirst() {
return this._first;
}
public Options second(String s) {
this._second = s;
return this;
}
public String getSecond() {
return this._second;
}
}
}
Of course, if you also wanted to allow positional arguments, you could define a Foo
constructor accepting them. To avoid having arguments logic repeated in both Foo
and Foo.Options
, that constructor would probably just call the Foo.Options
version, e.g.:
// *Optional* additional positional constructor for `Foo`
public Foo(String first, String second) {
this((new Foo.Options()).first(first).second(second));
}
Here's the code and usage from the answer I misread originally. The big difference is that instead of Foo.Options
, we have Foo.Builder
, and Foo.Builder
returns a Foo
when we ask it to build:
Foo foo = Foo.builder()
.setColor(red)
.setName("Fred")
.setSize(42)
.build();
Here's Foo
and Foo.Builder
:
public class Foo {
public static class Builder {
public Foo build() {
return new Foo(this);
}
public Builder setSize(int size) {
this.size = size;
return this;
}
public Builder setColor(Color color) {
this.color = color;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
// you can set defaults for these here
private int size;
private Color color;
private String name;
}
public static Builder builder() {
return new Builder();
}
private Foo(Builder builder) {
size = builder.size;
color = builder.color;
name = builder.name;
}
private final int size;
private final Color color;
private final String name;
// The rest of Foo goes here...
}
Upvotes: 1