How to specify a parameter

L

Luca D.

Hello!
When I create an instance of a class, I have to specify a direction,
which can be "Left" or "Right".
I thought about:

public class Object {
private String direction;

public Object(String direction) {
this.direction = direction;
}
}

Object o = new Object("Left"/"Right");

Otherwise:

public class Object {
private final int left = 0;
private final int right = 1;
private int direction;

public Object(int direction) {
this.direction = direction;
}
}

Object o = new Object(0/1);

In this case everyone must know that left = 0 and right = 1.
Is there a common way/design pattern to solve this kind of problem?
Thank you.
 
G

grasp06110

Hello!
When I create an instance of a class, I have to specify a direction,
which can be "Left" or "Right".
I thought about:

public class Object {
private String direction;

public Object(String direction) {
this.direction = direction;
}

}

Object o = new Object("Left"/"Right");

Otherwise:

public class Object {
private final int left = 0;
private final int right = 1;
private int direction;

public Object(int direction) {
this.direction = direction;
}

}

Object o = new Object(0/1);

In this case everyone must know that left = 0 and right = 1.
Is there a common way/design pattern to solve this kind of problem?
Thank you.

Hi,

Good question (shows lots of thought towards design that will save you
a heart ache in the long run if you continue to think of these things
up front rather than wait for a project to get large enough and
complex enough for these things to become significant).

If you are using a more recent version of Java (1.5 or higher) you can
use an enumeration (google java enumeration should give you everything
you need). 1.4 or earlier it was common to do something like declare a
public static final variables, something like:

public class Thingy {

public static final int LEFT = 0;

public static final int RIGHT = 1;

private int direction;

public Thingy(int initDirection) {
this.direction = initDirection;
}

}

Thingy thing = new Thingy(Thingy.LEFT);

Also, Josh Bloch had a very good book of idioms called Effective Java
that had an excellent section that described how to roll your own
enumerations in Java pre 1.5.

Have Fun,
John
 
E

Eric Sosman

Luca said:
Hello!
When I create an instance of a class, I have to specify a direction,
which can be "Left" or "Right".
I thought about:

public class Object {

Perhaps you should name your class "String" or "System"
to avoid confusion. ;-)
private String direction;

public Object(String direction) {
this.direction = direction;
}
}

Object o = new Object("Left"/"Right");

Otherwise:

public class Object {
private final int left = 0;
private final int right = 1;
private int direction;

public Object(int direction) {
this.direction = direction;
}
}

Object o = new Object(0/1);

In this case everyone must know that left = 0 and right = 1.
Is there a common way/design pattern to solve this kind of problem?

Several, with various advantages and disadvantages.

public class Obtuse {
public static final int LEFT = 0;
public static final int RIGHT = 1;

private int direction;

public Obtuse(int direction) {
this.direction = direction;
}
}
...
Obtuse o = new Obtuse(Obtuse.LEFT);

Advantage: Simplicity. Disadvantage: Allows `new Obtuse(-42)'.

public class Obnoxious {
private static class Direction {
private Direction() { }
}
public static final Direction LEFT = new Direction();
public static final Direction RIGHT = new Direction();

private Direction direction;

public Obnoxious(Direction direction) {
this.direction = direction;
}
}
...
Obnoxious o = new Obnoxious(Obnoxious.LEFT);

Advantage: Built-in type safety. Disadvantage: Clutter.

public class Obese {
public enum Direction { LEFT, RIGHT }

private Direction direction;

public Obese(Direction direction) {
this.direction = direction;
}
}
...
Obese o = new Obese(Obese.LEFT);

Advantage: It's all the rage. Disadvantage: More clutter.
 
R

Roedy Green

In this case everyone must know that left = 0 and right = 1.
Is there a common way/design pattern to solve this kind of problem?

1. boolean

2. named boolean e.g. final static boolean LEFT = false;

3. named int constant e.g. final static int LEFT = 0;

4. enum {lEFT,RIGHT;}
 
M

Mark Space

Roedy said:
4. enum {lEFT,RIGHT;}

This is the best idea. enum {LEFT, RIGHT} is type safe and much better
than ints or strings.

(Also, do NOT use a class named Object. Hello?)

If for some reason you are using an older compiler that doesn't have
enums, take grasp's advice and get Effective Java. The pattern uses
classes instead of ints. This makes the constants you expose much more
type safe. From memory, it goes something like this.


final public class Direction {

public final static Direction LEFT = new Direction();
public final static Direction RIGHT = new Direction();

private Direction() {
}
}

This can get fancier (you should probably override the toString()
method), but that's the gist. Now you have Direction.LEFT and
Direction.RIGHT, and no one can ever change that, or substitute a
different type or value. The type is Direction, as in

public void someMethod ( Direction dir ) { ... }.
 
L

Luca D.

Thanks everyone, I think Enums are the best solution in my case.
(Also, do NOT use a class named Object. Hello?)

Of course that was just a (bad) example.. Hello? World :)
 
M

Mark Space

Luca said:
Thanks everyone, I think Enums are the best solution in my case.


Of course that was just a (bad) example.. Hello? World :)

Yes it was. I think we all knew that, but we also get folks who have
named their own class Vector, or String, or Integer, and a big mess
usually ensues. I'll admit it was the first time I'd seen anyone use
Object though.

This group prefers precision, just because people do make those kinds of
mistakes. It's best post real code, and compilable code too, not just
snippets. Silly examples will get you flak from folks who assume that
what you posted is in fact what your code is.

Check out the SSCCE and try to do that. It'll also help you get answers
quicker:

<http://homepage1.nifty.com/algafield/sscce.html>
 
L

Luca D.

Let's see another example about the same topic.

public abstract class AbstractVehicle {
public String GetType();
}

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public String GetType() {
return "Vehicle1";
}
}

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public String GetType() {
return "Vehicle2";
}
}

public class VehicleManager {
public void DoSomething(AbstractVehicle vehicle) {
if(vehicle.GetType.equals("Vehicle1"))
...
else if(vehicle.GetType.equals("Vehicle2"))
...
...
}
}

Which is the best way to plan this situation with polymorphism?
Thanks to what you taught me, I'd use an enum:

public enum VehicleType {
VEHICLE1,
VEHICLE2
}

And the rest of the code would be:

public abstract class AbstractVehicle {
public VehicleType GetType();
}

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public VehicleType GetType() {
return VehicleType.VEHICLE1;
}
}

public abstract class ConcreteVehicle2 extends AbstractVehicle {
public VehicleType GetType() {
return VehicleType.VEHICLE2;
}
}

public class VehicleManager {
public DoSomething(AbstractVehicle vehicle) {
if(vehicle.GetType() == VehicleType.VEHICLE1)
...
else if(vehicle.GetType() == VehicleType.VEHICLE2)
...
...
}
}

Is it good to use an enumerator which contains the type/name of every
subclass?
Hoping this time the names for classes I used are better, thanks in
advance! :)
 
R

Roedy Green

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public VehicleType GetType() {
return VehicleType.VEHICLE1;
}
}

why not just append your ConcreteVehicle1 methods to the VEHICLE1
enum? Then you don't even need a getType method.
 
R

RedGrittyBrick

Luca said:
Let's see another example about the same topic.

public abstract class AbstractVehicle {
public String GetType();
}

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public String GetType() {
return "Vehicle1";
}
}

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public String GetType() {
return "Vehicle2";
}
}

public class VehicleManager {
public void DoSomething(AbstractVehicle vehicle) {
if(vehicle.GetType.equals("Vehicle1"))
...
else if(vehicle.GetType.equals("Vehicle2"))
...
...
}
}

Which is the best way to plan this situation with polymorphism?
Thanks to what you taught me, I'd use an enum:

public enum VehicleType {
VEHICLE1,
VEHICLE2
}

And the rest of the code would be:

public abstract class AbstractVehicle {
public VehicleType GetType();
}

public abstract class ConcreteVehicle1 extends AbstractVehicle {
public VehicleType GetType() {
return VehicleType.VEHICLE1;
}
}

public abstract class ConcreteVehicle2 extends AbstractVehicle {
public VehicleType GetType() {
return VehicleType.VEHICLE2;
}
}

public class VehicleManager {
public DoSomething(AbstractVehicle vehicle) {
if(vehicle.GetType() == VehicleType.VEHICLE1)
...
else if(vehicle.GetType() == VehicleType.VEHICLE2)
...
...
}
}


The above is riddled with bugs.
Is it good to use an enumerator which contains the type/name of every
subclass?

1) Maybe you could use vehicle.getClass().getName() instead?

2) The need to do so suggests the design is poor. Whatever is happening
in the 'if' statements, should perhaps be replaced by an instance method
of AbstractVehicle that the subtypes implement (or override) differently.

Instead of
if(vehicle.GetType() == VehicleType.VEHICLE1)
...
else if(vehicle.GetType() == VehicleType.VEHICLE2)
...
...
Maybe you can do
vehicle.dotDotDot();


Here's a corrected SSCCE based on your buggy code above:
---------------------------------------8<---------------------------------
public class InheritTest1 {
public static void main(String[] args) {
InheritTest1 x = new InheritTest1();
x.new VehicleManager().doSomething(x.new ConcreteVehicle1());
}

public enum VehicleType {
VEHICLE1, VEHICLE2
}

public abstract class AbstractVehicle {
public abstract VehicleType getType();
}

public class ConcreteVehicle1 extends AbstractVehicle {
public VehicleType getType() {
return VehicleType.VEHICLE1;
}
}

public class ConcreteVehicle2 extends AbstractVehicle {
public VehicleType getType() {
return VehicleType.VEHICLE2;
}
}

public class VehicleManager {
public void doSomething(AbstractVehicle vehicle) {
if (vehicle.getType() == VehicleType.VEHICLE1)
System.out.println("Aha!");
else if (vehicle.getType() == VehicleType.VEHICLE2)
System.out.println("Oho!");
}
}

}
---------------------------------------8<---------------------------------
The main is a bit convoluted just so I can wrap everything into a single
class for ease of cut&paste&compile.

Here's another (better?) way to do achieve the same outcome:
---------------------------------------8<---------------------------------

public class InheritTest2 {
public static void main(String[] args) {
InheritTest2 x = new InheritTest2();
x.new VehicleManager().doSomething(x.new ConcreteVehicle1());
}


public abstract class AbstractVehicle {
public abstract void doSomething();
}

public class ConcreteVehicle1 extends AbstractVehicle {
public void doSomething() {
System.out.println("Aha!");
}
}

public class ConcreteVehicle2 extends AbstractVehicle {
public void doSomething() {
System.out.println("Oho!");
}
}

public class VehicleManager {
public void doSomething(AbstractVehicle vehicle) {
vehicle.doSomething();
}
}

}
---------------------------------------8<---------------------------------
Whether the above meets your needs is something I can't determine from
the example you posted. I think it illustrates a better way to think
about such problems but there will be some needs that can't be handled
this way.

Hoping this time the names for classes I used are better,

Much better :)

I'd have used Car and Truck instead of ConcreteVehicle1 and
ConcreteVehicle2 but maybe I have too much difficulty with abstract
expressions of concepts.
 
L

Luca D.

why not just append your ConcreteVehicle1 methods to the VEHICLE1
enum?  Then you don't even need a getType method.

Do you mean to remove the subclasses and work directly with the enum?
I think I can't do that because ConcreteVehicles are Thread.
 
L

Luca D.

Instead of
        if(vehicle.GetType() == VehicleType.VEHICLE1)
            ...
        else if(vehicle.GetType() == VehicleType.VEHICLE2)
            ...
        ...
Maybe you can do
        vehicle.dotDotDot();

I can't do that, the Manager can't delegate the vehicles in this way,
it must know the type of vehicle to do other things..
Maybe the best solution is x.getClass().getName() and then check the
String.
Thanks for all your answers!
 
L

Lew

Luca said:
I can't do that, the Manager can't delegate the vehicles in this way,
it must know the type of vehicle to do other things..
Maybe the best solution is x.getClass().getName() and then check the
String.

No, RedGrittyBrick's solution is the best.

Your statement "I can't do that" is actually mistaken.

Checking the type and branching is an antipattern for which polymorphism is
the solution.

If your [Mis]Manager class "must know the type of the vehicle", then you
aren't taking advantage of the object-oriented programming skill set. You
have broken encapsulation.

The vehicle must be the only thing that knows how to fulfill its public
contract. Whatever the Manager wants to do is better handled via a
polymorphic method call.
 
M

Mark Space

Luca said:
I can't do that, the Manager can't delegate the vehicles in this way,
it must know the type of vehicle to do other things..
Maybe the best solution is x.getClass().getName() and then check the
String.
Thanks for all your answers!

I have to ditto what Lew and Red said. I don't like the enums either,
anytime you need to do this it's basically broken. It feels like you're
trying to implement one of those "roll your own RTTI" systems people
feel they need to use with C++.

I'm curious: what Manager you are using? Did you get it as part of a
package or did your team write it themselves?
 

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,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top