A class that uses instances of itself? Is this right?

M

Miguel Farah

I was recently sent some Java code that I find VERY odd. Among several
other things, all the ValueObject classes are like this example:

----8<--------8<--------8<--------8<--------8<--------8<--------8<----
package this.cant.be.right;
import java.io.Serializable;

public class WhatTheHell implements Serializable {
private String text;

public static WhatTheHell
HELLO = new WhatTheHell("HELLO"),
WORLD = new WhatTheHell("WORLD"),
DAZED = new WhatTheHell("DAZED"),
CONFUSED = new WhatTheHell("CONFUSED"),
DAMMIT = new WhatTheHell("DAMMIT");

protected WhatTheHell(String text) {
super();
this.text = text;
}

public String getText() {
return text;
}

}
----8<--------8<--------8<--------8<--------8<--------8<--------8<----

There are some obvious flaws: the setText() method is missing and the
constructor uses super() even though it doesn't extend anything
(besides
Object, that is).

However, what I REALLY find odd is the static atributes HELLO, WORLD,
etcetera, as instances of the class itself. The guy that did this
states
this lets him restrict the the constants that might be used to
instantiate objects of this class.

*I* find this very odd, and have serious doubts about it. Since I'm not
yet expert at Java, I could be mistaken, and this is why I ask you guys
to tell me wether I'm right or wrong. Have you seen this before? Is it
considered a good practice? Or not?

Thanks in advance.
 
A

Andrea Desole

Miguel said:
However, what I REALLY find odd is the static atributes HELLO, WORLD,
etcetera, as instances of the class itself. The guy that did this
states
this lets him restrict the the constants that might be used to
instantiate objects of this class.

*I* find this very odd, and have serious doubts about it. Since I'm not
yet expert at Java, I could be mistaken, and this is why I ask you guys
to tell me wether I'm right or wrong. Have you seen this before? Is it
considered a good practice? Or not?

although i haven't seen it very often implemented, this guy is probably
not wrong. This approach is (better to say was) used to implement safe
enumerations in Java. Please check this link:


http://java.sun.com/developer/Books/shiftintojava/page1.html#replaceenums
 
R

Rogan Dawes

Miguel said:
I was recently sent some Java code that I find VERY odd. Among several
other things, all the ValueObject classes are like this example:

----8<--------8<--------8<--------8<--------8<--------8<--------8<----
package this.cant.be.right;
import java.io.Serializable;

public class WhatTheHell implements Serializable {
private String text;

public static WhatTheHell
HELLO = new WhatTheHell("HELLO"),
WORLD = new WhatTheHell("WORLD"),
DAZED = new WhatTheHell("DAZED"),
CONFUSED = new WhatTheHell("CONFUSED"),
DAMMIT = new WhatTheHell("DAMMIT");

protected WhatTheHell(String text) {
super();
this.text = text;
}

public String getText() {
return text;
}

}
----8<--------8<--------8<--------8<--------8<--------8<--------8<----

There are some obvious flaws: the setText() method is missing and the
constructor uses super() even though it doesn't extend anything
(besides
Object, that is).

However, what I REALLY find odd is the static atributes HELLO, WORLD,
etcetera, as instances of the class itself. The guy that did this
states
this lets him restrict the the constants that might be used to
instantiate objects of this class.

*I* find this very odd, and have serious doubts about it. Since I'm not
yet expert at Java, I could be mistaken, and this is why I ask you guys
to tell me wether I'm right or wrong. Have you seen this before? Is it
considered a good practice? Or not?

Thanks in advance.

This code basically provides a limited number of predefined instances of
the class. This allows you to write code that specifically handles those
particular instances, and not worry about handling the other instances.

In your example, the class is immutable. Hence there is no need for a
setText(String) method, the text is set once at instantiation, and
cannot be changed. Calling super() is just a convention. In fact, if you
don't call it explicitly as the first instruction in the constructor, my
understanding is that the compiler inserts an implicit super() call anyway.

For another example of where this may be used, consider java.awt.Color,
where, although you can create your own colors, they also create a
number of default colors as static variables.

e.g. java.awt.RED, etc

Regards,

Rogan
 
C

Chris Uppal

Miguel said:
There are some obvious flaws: the setText() method is missing and the
constructor uses super() even though it doesn't extend anything
(besides Object, that is).

setText() is probably missing because these objects are intended to be
immutable.

The call to super() is logically unnecessary, but it does no harm (especially
because the compiler /by definition/ will insert a call to super() if you don't
write one explicitly).

However, what I REALLY find odd is the static attributes HELLO, WORLD,
etcetera, as instances of the class itself. The guy that did this
states
this lets him restrict the the constants that might be used to
instantiate objects of this class.

Yes, this class is intended to have a fixed number of known instances. You are
not intended to be able to create any others, because that is not how the class
is intended to be used. (Although the author of the code has not forbidden
subclasses from creating further instances).

*I* find this very odd, and have serious doubts about it. Since I'm not
yet expert at Java, I could be mistaken, and this is why I ask you guys
to tell me wether I'm right or wrong. Have you seen this before? Is it
considered a good practice? Or not?

It's not a /typical/ class, but it is by no means unusual. It's a fairly
common idiom in cases where, by design, the class is supposed to have a fixed
set of well-known instances. Two common(ish) examples are the Singleton
pattern (of which this is a sort of generalisation) and to implement
"enum"-like constructions. In fact something similar (though more elaborate)
is used internally to implement the new enum classes in Java 5.0. For
instance, if you wanted to represent primary colours, then you might use this
technique to create a class with just three instances: PrimaryColor.RED,
PrimaryColor.BLUE, PrimaryColor.GREEN.

One particular advantage of the technique is that the instances can be compared
directly by ==, rather than requiring a more verbose/expensive/error-prone
comparison using equals():

if (lamp.getColor() == PrimaryColor.RED)
{
// ah, good. A brothel...
}
else if (lamp.getColor() == PrimaryColor.BLUE)
{
// damn, a police station. Run away...
}
else
{
// ?? WTF ?? What's a green lamp supposed to mean ?
}

I think the class (as you've paraphrased it) has one error. The class
implements Serializable, so the objects are clearly intended to be serialized,
but the class does not have the correct machinery to support that. Perhaps
you've just deleted that code.

-- chris
 
R

Rene

Miguel Farah said:
I was recently sent some Java code that I find VERY odd. Among several
other things, all the ValueObject classes are like this example:

----8<--------8<--------8<--------8<--------8<--------8<--------8<----
package this.cant.be.right;
import java.io.Serializable;

public class WhatTheHell implements Serializable {
private String text;

public static WhatTheHell
HELLO = new WhatTheHell("HELLO"),
WORLD = new WhatTheHell("WORLD"),
DAZED = new WhatTheHell("DAZED"),
CONFUSED = new WhatTheHell("CONFUSED"),
DAMMIT = new WhatTheHell("DAMMIT");

protected WhatTheHell(String text) {
super();
this.text = text;
}

public String getText() {
return text;
}

}
----8<--------8<--------8<--------8<--------8<--------8<--------8<----

There are some obvious flaws: the setText() method is missing and the

This is intentional in this code. The author only want the static
instantiated objects to be present and have them unchangeable. This is a
form of enumeration. Prior to Java 1.5 this was one of the ways to do it.
You cannot redefine the pre-instantiated objects you can only "get" them as
read-only objects.
constructor uses super() even though it doesn't extend anything
(besides
Object, that is).

If you leave out super() as first call in a constructor, Java does that
automagically for you. Nothing fishy about it, but you can remove the line.
This has no change to the resulting behaviour.
However, what I REALLY find odd is the static atributes HELLO, WORLD,
etcetera, as instances of the class itself. The guy that did this
states
this lets him restrict the the constants that might be used to
instantiate objects of this class.

Yes, I believe this was the intention. You'll probably find in the package
some comparisions against these states. You can add new ones only by
extending this class and you cannot change already existing ones. Of course
there can be problems when suddenly 3 classes extend this class and know
nothing of each other. This is one of the caveats of doing it that way.

Java 1.5 knows an enumeration type that solves this kind of problems - but
I haven't had a close look at it, I'm still stuck at 1.4
*I* find this very odd, and have serious doubts about it. Since I'm not
yet expert at Java, I could be mistaken, and this is why I ask you guys
to tell me wether I'm right or wrong. Have you seen this before? Is it
considered a good practice? Or not?

There are definitely worse ways to do it. With the limited scope I can only
give a limited answer and that is: It is not bad. It might not be good
either, though. However your confusion tells me the code is not or badly
documented, which definitely is bad. There should be a description of what
these Thingies are used for.

CU

Rene
 
A

Andrew McDonagh

Miguel said:
I was recently sent some Java code that I find VERY odd. Among several
other things, all the ValueObject classes are like this example:

----8<--------8<--------8<--------8<--------8<--------8<--------8<----
package this.cant.be.right;
import java.io.Serializable;

public class WhatTheHell implements Serializable {
private String text;

public static WhatTheHell
HELLO = new WhatTheHell("HELLO"),
WORLD = new WhatTheHell("WORLD"),
DAZED = new WhatTheHell("DAZED"),
CONFUSED = new WhatTheHell("CONFUSED"),
DAMMIT = new WhatTheHell("DAMMIT");

protected WhatTheHell(String text) {
super();
this.text = text;
}

public String getText() {
return text;
}

}
----8<--------8<--------8<--------8<--------8<--------8<--------8<----

There are some obvious flaws: the setText() method is missing and the
constructor uses super() even though it doesn't extend anything
(besides
Object, that is).

However, what I REALLY find odd is the static atributes HELLO, WORLD,
etcetera, as instances of the class itself. The guy that did this
states
this lets him restrict the the constants that might be used to
instantiate objects of this class.

*I* find this very odd, and have serious doubts about it. Since I'm not
yet expert at Java, I could be mistaken, and this is why I ask you guys
to tell me wether I'm right or wrong. Have you seen this before? Is it
considered a good practice? Or not?

Thanks in advance.

Everything that the others have said is correct. However, I thought it
may help you to see why & how this pattern is used in Java.

Because Java (up until 5.0) has no concept of 'enum' like C/C++/etc, we
can't typedef any enums.

Therefore we are limited to either having constants which are passed
around via native type (e.g. int, double, String, etc) , or by using the
'TypeSafe enum' pattern.


E.g.

public class SimplisticWhatTheHellEnum {
public static final String HELLO = "Hello";
public static final String GOODBYE = "GoodBye";
}


public void callMethodWithAnEnum() {
// what we hope everyone who uses this code would do.
aMethodDoingSomethingOnEnum(SimplisticWhatTheHellEnum.HELLO);

// Because the method parameter takes a 'String'
// any old 'String' value could be passed.
aMethodDoingSomethingOnEnum("not one of our enums");
}

public void aMethodDoingSomethingOnEnum(String enum) {
if (enum.equals(SimplisticWhatTheHellEnum.HELLO) {
...
} else {
// Have to handle unknown parameter value
}
}

Nothing really wrong with this method, but it does mean it could be
called with any String value, not just the constants defined somewhere.

However, with the TypeSafe Enum pattern, we would pass in instances of
our WhatTheHell enum object, which can't be substituted with any old value.

So using the TypeSafe enum you posted, the code becomes...

public void callMethodWithAnEnum() {
// everyone who uses this code can now only pass in instances
// of our WhatTheHell enum class.
aMethodDoingSomethingOnEnum(WhatTheHell.HELLO);

// not possible to compile the following line...
// aMethodDoingSomethingOnEnum("not one of our enums");
}

public void aMethodDoingSomethingOnEnum(WhatTheHell enum) {

// As the parameter MUST be an instance of our class, we know
// this method can not be called with any old string
// so we don't have to worry about unknowns.

if (enum.equals(SimplisticWhatTheHellEnum.HELLO) {
...
}
}

Also, once we have our own homegrown objects being passed around, rather
than Strings, 'int', double', etc, we can start to apply more advanced
OOP techniques to replace the if() statements with polymorphic calls
upon the enum objects. Something that is not possible with the Java
primitives and classes like String.

HTH

Andrew
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top