So I have a superclass GeoFig class, and two subclasses Cylinder and Sphere. I want to include one method in the superclass to calculate the volume(called setVolume), but each subclass has a different formula for calculating the volume. Through the subclass' constructors I will setVolume and will also getVolume. How do I do this?
-
2Show some code please. – Semih Eker Dec 02 '14 at 13:41
-
6Make `GeoFig` abstract with an abstract `setVolume()` method. In the subclasses you will provide the implementation of the method. – Konstantin Yovkov Dec 02 '14 at 13:42
-
Having `setVolume` is problematic for a Cylinder since you don't know how to apportion the volume between the length and the cross-section. – Bathsheba Dec 02 '14 at 13:43
-
Oracle has a [tutorial section](https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) that explains everythong you need to know to start java. – jhamon Dec 02 '14 at 13:43
-
I must have the method in the superclass, with no abstract method. – noobforce Dec 02 '14 at 13:43
-
I forgot to mention, when I create a Cylinder, I give it a radius and a height. When I create a Sphere, I give it a radius. – noobforce Dec 02 '14 at 13:44
-
1What will `setVolume` actually do? – Bathsheba Dec 02 '14 at 13:44
-
3@noobforce: `"I must have the method in the superclass, with no abstract method."` - Then your design is wrong. A `GeoFig` is an abstract concept, it should be an abstract class. Each inherited class has its own implementation of determining volume, so each should override an abstract member for making that determination. Also, there should be no `setVolume` because volume is calculated based on other metrics. – David Dec 02 '14 at 13:46
-
Sorry for not making it clear. GeoFig contains a private double field called volume. setVolume will make volume equal to whatever the formula for calculating the shape's volume is. – noobforce Dec 02 '14 at 13:46
-
1@noobforce: `"setVolume will make volume equal to whatever the formula for calculating the shape's volume is."` - That makes no sense. For example, what are the dimensions of a cylinder with a volume of 5 cubic units? There's insufficient data to calculate that. `"GeoFig contains a private double field called volume."` - Also incorrect. Volume isn't stored, it's calculated. It can be temporarily cached for performance (not really necessary though, these are small calculations) and the cache invalidated when a dimension of the shape changes, but it's not actually stored. – David Dec 02 '14 at 13:49
-
@noobforce Then remove that private field and the `setVolume` method and do what the others suggest. – isnot2bad Dec 02 '14 at 13:49
1 Answers
My Java is very rusty, so consider any code here to be pseudo-code just to demonstrate the concepts...
You're not modeling the objects in code correctly. The code should match the real-world concepts being modeled. So let's consider those real-world concepts.
What is a GeoFig
?
What does one look like? If you held one in your hand, what shape would it be? There's no answer to that, because it's not a concrete object. It's a conceptual or abstract object. So it should be an abstract class:
abstract class GeoFig { }
What attributes describe a GeoFig
?
Does it have a length? A width? A radius? Not really, no. But for the purposes of being an object in 3-dimensional space we can assume that it has a volume. We just don't know how to calculate that volume:
abstract class GeoFig {
abstract double getVolume();
}
Now we have our parent class.
What is a Cylinder
?
It's a geometric object with a volume, so we can inherit from the parent class:
class Cylinder inherits GeoFig {
public double getVolume() {
return 0;
}
}
How do we calculate the volume of a Cylinder
?
π * r^2 * h
But we don't have r
or h
yet...
What attributes describe a Cylinder
?
It has a height and a radius. In fact, it must have these to exist at all. So it requires them for object construction:
class Cylinder inherits GeoFig {
private final double height;
private final double radius;
public Cylinder(double height, double radius) {
this.height = height;
this.radius = radius;
}
public double getHeight() {
return this.height;
}
public double getRadius() {
return this.radius;
}
double getVolume() {
return 0;
}
}
(This assumes immutability. Make appropriate changes if you want to be able to change the dimensions of a Cylinder
.)
Now we can also calculate the volume:
double getVolume() {
return Math.PI * this.radius * this.radius * this.height;
}
Repeat the same logical process for any other shapes.
-
I understand what you are saying now. Sorry for being stubborn before. However, I am also supposed to have a private field volume and my teacher will not allow me to remove it. He said I need to use method overriding or possibly super or this. How do I do this? Is it the only way to not use the volume field at all? – noobforce Dec 03 '14 at 13:57
-
ALso another question, is it possible to run a method in a superclass if a method with the same name and parameter in the subclass is overriden? – noobforce Dec 03 '14 at 14:10
-
@noobforce: I believe that varies by language (I'm much more experienced with C# than with Java) and by the different ways in which something may be overridden, so I can't speak to that with absolute authority. It's certainly worth testing. There could be a way to invoke something like `base.methodName()` or `super.methodName()` or something like that from within the child class' overriding method. Be careful not to break abstractions though, by overriding methods with a different semantic *meaning* and obscuring the original meaning of the parent method. – David Dec 03 '14 at 14:14