Abtract Base Class Design problem

B

Bernd

Hi,

I am having a problem to design

I got an abstract base class Base and
a couple of concrete subclasses, say
Child1 and Child2. With every class that is derived from
Base certain "cost" is associated
(a value, that despends only on the subclass, not on a
speific object of that class).
Now I would like to do the following:

1) Ask a subclass about its costs:
Child1.getCosts() // would return 10, because class Child1 costs 10
Child1.getCosts(); // would return 20, because class Child2 costs 20

2) ask a specific object about the costs of its subclass:
Child1 c1 = new Child1();
c1.getCosts() // would return 10, because class Child1 costs 10
Child1 c2 = new Child2();
c2.getCosts(); // would return 20, because class Child2 costs 20

3)ask a specific object about the costs of its subclass, but the reference
to the object is of class Base:
Base b;
b = new Child1();
b.getCosts() // would return 10, because class Child1 costs 10
b = new Child2();
b.getCosts(); // would return 20, because class Child2 costs 20

How do I design this?
(doesn't have to be a method getCosts(), could be via constants, etc)

I can't specify an abstract static method getCosts() in Base,
because Java does not allow that.
But if getCosts() is not static, I can't do Child1.getCosts().
If I leave it out of the base class, I always have to downcast every
Base object to its subclass, which I don't want, and there is
also no way to enforce the existence of a static getCosts function in
the subclasses.

I hope I made myself reasonable clear.

Please advice and thanks for you help.

Bernd
 
X

xarax

Bernd said:
Hi,

I am having a problem to design

I got an abstract base class Base and
a couple of concrete subclasses, say
Child1 and Child2. With every class that is derived from
Base certain "cost" is associated
(a value, that despends only on the subclass, not on a
speific object of that class).
Now I would like to do the following:

1) Ask a subclass about its costs:
Child1.getCosts() // would return 10, because class Child1 costs 10
Child1.getCosts(); // would return 20, because class Child2 costs 20

I assume you meant Child2, not Child1.
2) ask a specific object about the costs of its subclass:
Child1 c1 = new Child1();
c1.getCosts() // would return 10, because class Child1 costs 10
Child1 c2 = new Child2();
c2.getCosts(); // would return 20, because class Child2 costs 20

3)ask a specific object about the costs of its subclass, but the reference
to the object is of class Base:
Base b;
b = new Child1();
b.getCosts() // would return 10, because class Child1 costs 10
b = new Child2();
b.getCosts(); // would return 20, because class Child2 costs 20

How do I design this?
(doesn't have to be a method getCosts(), could be via constants, etc)

I can't specify an abstract static method getCosts() in Base,
because Java does not allow that.
But if getCosts() is not static, I can't do Child1.getCosts().
If I leave it out of the base class, I always have to downcast every
Base object to its subclass, which I don't want, and there is
also no way to enforce the existence of a static getCosts function in
the subclasses.

I hope I made myself reasonable clear.

Please advice and thanks for you help.

Bernd

public abstract class Base
{
protected final int cost;

public final int getCost()
{
return cost;
}

protected Base(final int theCost)
{
super();

cost = theCost;
}
}

public final class Child1
extends Base
{
private static final int COST = 10;

public static int COST()
{
return COST;
}

public Child1()
{
super(COST);
}
}

public final class Child2
extends Base
{
private static final int COST = 20;

public static int COST()
{
return COST;
}

public Child2()
{
super(COST);
}
}
 
C

Chris Uppal

xarax said:
public abstract class Base
[...]

Even simpler, if I've understood Bernd correctly, would be:

public abstract class Base
{
public abstract int getCost();
}

public class Child1()
{
public int getCost() { return 10; }
}

public class Child2()
{
public int getCost() { return 20; }
}

Why store a constant ?

-- chris
 
X

xarax

Chris Uppal said:
xarax said:
public abstract class Base
[...]

Even simpler, if I've understood Bernd correctly, would be:

public abstract class Base
{
public abstract int getCost();
}

public class Child1()
{
public int getCost() { return 10; }
}

public class Child2()
{
public int getCost() { return 20; }
}

Why store a constant ?

The constant may come from a properties file
or other external medium during class initialization.
It is also better documentation. Finally, my example
is a "static final int", which means that a constant
is not stored at all. The compiler replaces the
field usage with the in-line constant.

2 cents worth...eek!
 
B

Bernd

Chris Uppal said:
Even simpler, if I've understood Bernd correctly, would be:

public abstract class Base
{
public abstract int getCost();
}

public class Child1()
{
public int getCost() { return 10; }
}

public class Child2()
{
public int getCost() { return 20; }
}
No, that is unfortunately not possible,
because I cant' ask subclasses about their costs
(e.g. Child1.getCosts() does not work, because
getCosts() is not static).

Greetings

Bernd
 
B

Bernd

xarax said:
I assume you meant Child2, not Child1.

Yes, that was a typo.
[helpful code snipped]

Thanks, I think that was what I was looking for.
Actually, i did something very similar after I posted
my question.

But I still see some problems:

1) I am wasting space.
Every object now allocates an int for "cost", instead of
using just one int per subclass. In my application this
won't be a problem, so I don't really care.

2) There are two different ways to ask about costs :
Base b = new Child1();
b.getCosts();

and

Child1.COST();

This is a bit counter-intuitive.

3) I don't enforce the existence of a static COST() function
in every subclass of Base (probably not possible in Java).
Well, OTOH I have to call the super
constructor with costs and if I use Child1.COST() and the method
does not exist, I get a compile-time error, so I don't know
whether this is really a big disadvantage.



Might be, that these issues can't be solved in Java in a more elegant fashion
and your solution is the optimal one. If someone has a better
idea, please post.


Bernd
 
J

John C. Bollinger

Bernd said:
No, that is unfortunately not possible,
because I cant' ask subclasses about their costs
(e.g. Child1.getCosts() does not work, because
getCosts() is not static).

You cannot have a static method and an instance method of the same class
with the same signature. Also, static methods are not polymorphic, so
there is no way to specify in a base class anything about static members
of a subclass. You could modify Chris' solution to accomodate, however:

public abstract class Base {
public abstract int getCost();
}

public class Child1() {
public int getCost() { return Child1.getCostStatic(); }
public static int getCostStatic() { return 10; }
}

public class Child2() {
public int getCost() { return Child2.getCostStatic(); }
public static int getCostStatic() { return 20; }
}


Call the static methods by whatever name you like, as long as the names
don't collide with those of the instance methods. Their presence and
names are only a convention you establish, however.


John Bollinger
(e-mail address removed)
 
C

Chris Uppal

Bernd said:
No, that is unfortunately not possible,
because I cant' ask subclasses about their costs
(e.g. Child1.getCosts() does not work, because
getCosts() is not static).

Right, I'd missed that in your list of requirements.

public abstract class Base
{
public abstract int getCost();
}

public class Child1()
{
public static final int INSTANCE_COST = 10;
public int getCost() { return INSTANCE_COST; }
}

public class Child2()
{
public static final int INSTANCE_COST = 20;
public int getCost() { return INSTANCE_COST; }
}

There is, of course, no particular magic that happens because the static fields
have the same name -- there is no semantic connection between them, but it
generally helps client programmers if there's some consistency.

Note that I've chosen to provide access to the constants as exposed fields, I
could have used static methods (as John Bollinger suggests), but I prefer this
way by a small margin. The main reason is that I feel that the difference
(method vs. field) does something to ameliorate the potential confusion in
programmers minds (those that have minds ;-) "which am I supposed to use ?"
since we are accustomed to seeing class constants exposed as static final
fields, and polymoprphically varying behaviour exposed as instance methods.

-- chris
 
C

Chris Uppal

xarax said:
The constant may come from a properties file
or other external medium during class initialization.

No, I'd meant why store the constant in the abstract base class's
"instances" -- it commits the subclasses to an implementation strategy that may
be inappropriate (e.g. the value may be genuinely constant -- fixed at compile
time -- in which case there is no need to store it), and as a result places an
unwanted responsibility on them (to provide the value of the constant in the
constructor, which may be pointless).

It is also better documentation.

I'd dispute that. If the constant in used in other contexts, then eliminating
the duplication by using a named constant is obviously a Good Thing. But the
context here is doesn't seem to be like that -- the method getCost() is *the*
"exposed constant" and as such *its* name is the one that provides the
documentation (or fails to). There's no documentary difference between

public final int SOME_USEFUL_NAME = 127;

and

public int someUsefulName() { return 127; }

provided, as I say, that the member in question is the sole "point of contact"
for the actual value, 127.

Finally, my example
is a "static final int", which means that a constant
is not stored at all. The compiler replaces the
field usage with the in-line constant.

Actually the static final int variable *is* still stored -- it's needed for
reflection, JNI, etc. You are right -- of course -- that references to it are
compiled away. (BTW did you realise that this applies to *all* final
int/etc/String fields that are initialised with a compile-time constant -- not
just to static ones ? I didn't up until a week or two ago. I haven't yet
thought of any use for it, but it's a moderately surprising bit of trivia...)

-- chris
 

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,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top