OOP Task (class hierarchy, inheritance, interface, etc.)

2.2k views Asked by At

Since I am trying to learn more about OOP (Java) I'm working my way through some literature where I found this 'task'. Unfortunately I am having kind of a hard time since I am pretty new to OOP and I don't have any sample solution to this. Maybe some of you can give me some input so can work my way through this.


  1. Define a class hierarchy for these classes:
    • quadrilateral
    • convex quadrilateral
    • trapezoid
    • parallelogram
    • rhombus
    • rectangle
    • square
  2. Create an instance of each class if possible
  3. Define reasonable attributes and methods in each class
  4. Overload and override methods
  5. Write reasonable constructors for each class
  6. Use modifiers (abstract, static, final, public, protected and private) in a meaningful way
  7. How could an interface be used for this task?

01 Class hierarchy

Okay, this is simple math and you can find tons of information on the hierarchy of quadrilaterals everywhere. Here is what I did:

enter image description here


Creating Objects of each class is no big deal, but I still have some problems with understanding all the OOP-techniques. There are some points where I don't know what would be the better way to do it... (e.g. the square which inherits from two classes, which in java is simply not possible). Also, formulas (like calculating the surface area) would be overwritten all the time anyhow (since they are different most of the time), so why would I need inheritance anyway? Couldn't I just use an interface, use it in all of those classes an force them to implement these formulas?

Greetings - Vulpecula

3

There are 3 answers

0
LogicChains On BEST ANSWER

In real life, you probably would be better off using an interface. Deep inheritance structures like that are often frowned upon; it's generally considered good to 'prefer composition over inheritance' (http://en.wikipedia.org/wiki/Composition_over_inheritance). You might for instance have a 'quadrilateral' interface that defines 'surface area' and 'perimeter', and then have the other shapes satisfy that interface.

If this is a homework question however, then you should probably base the class hierarchy on whatever examples your textbook/teacher have provided previously. It's not about designing robust software, it's about proving to your teacher that you learned how to do things in whatever way they think you should do them.

0
Vulpecula On

Okay, the plan now is that I am trying to resolve this without any interface first. So here's the map of inheritance:

I am ignoring the fact, that the square is not only a rectange but also a rhombus.

The abstract class (quadrilateral) will define (but not implement) methods for calculating 'surface area' and 'perimeter'. Overriding methods is easy since every shape has different formumals for calculation but I am not really sure where I could use the overloading feature.


One more thing: Using an interface, would this be the desired way?

enter image description here

6
aliteralmind On

An abstract class as the base of a moderately complicated hierarchy is not as flexible as an interface. A class--abstract or not--forces a specific type of implementation.

Without thinking too hard about it, here's one way to start:

public interface Quadrilateral  {
   int getTopMillimeters();
   int getLeftMillimeters();
   int getRightMillimeters();
   int getBottomMillimeters();
}

From this raw data, you could also define

getTopLeftAngle(), getTopRightAngle(), ...

which would all compute their values based on the lengths.

I too would emphasize composition over inheritance. The end-effect can indeed be a complex inheritance structure.

For me, composition is heirarchy of "Composer" classes, which do NOT implement the interface. Such as

public class QuadrilateralComposer  {
   private final int iTopMM;
   private final int iBtmMM;
   ...
   public QuadrilateralComposer(int i_topMM, int i_bottomMM, ...)  {
      if(i_topMM < 1)  {
         throw  new IllegalArgumentException...
      }
      if(i_bottomMM < 1)  {
         throw  new IllegalArgumentException...
      }
      ...
      iTopMM = i_topMM;
      iBtmMM = i_bottomMM;
      ...
   }
   public int getTopMillimeters()  {
      return  iTopMM;
   }
   ...

Which is then composed by an abstract class:

public class AbstractQuadrilateral implements Quadrilateral
   private final QuadrilateralComposer qc;
   public AbstractQuadrilateral(int i_topLen, int i_bottomLen, ...)  {
      gc = new QuadrilateralComposer(i_topLen, i_bottomLen, ...);
   }
   public int getTopLength()  {
      return  gc.getTopLength();
   }
   ...

Abstract classes never extend other abstract classes, they only use internal Composers (and actually implement the interface). On the other end, Composers only extend Composers, and use other composers internally.

(Three notes: Protected functions are in the Composer as public function_4prot() and are implemented as protected function(), which call the _4prot version. And sometimes the abstract class can indeed implement everything in the interface. In this case, it would be concrete [non-abstract] and be named "SimpleXYZ", instead of "AbstractXYZ". Finally, static utility functions reside in the Composer.)

If EVERY interface is designed in this way, then ANY class can easily implement ANY interface, regardless which class they must actually extend. If abstract classes extend other abstract classes, that is a lot more work for classes that need to implement the interface, but happen to--and have to--extend something else.

This is not what you asked, but learning this concept changed my code for the WAY better. Seeing it mentioned in the accepted answer made me think through all of it. I've actually been slowly drifting away from inheritance to composition over the past few years, and after reading Effective Java, it was the final nail in the inheritance coffin, as it were.