Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hierarchical Object Design (Java)

Tags:

oop

I am looking for an elegant design for a problem analogous to the following:

A story can have a flexible hierarchical structure. It might consist of several books, each of which have chapters, each of which have sections, each of which contain text. Or, it might simply have sections (a short story for instance). Or it might just consist of chapters that have sections. In all situations, you mustn't be allowed to mix styles (so you couldn't add a chapter to a story based on books, you would have to add the chapter to the book itself).

I have come up with a couple of design solutions for this type of problem but they get messy. Is there a clean way to represent this so that, given a reference to a Story class I can get access to the content in a clear, systematic fashion?

like image 540
Julian Gold Avatar asked Oct 22 '25 09:10

Julian Gold


2 Answers

Its kind of tricky situation because the concepts like "Books", "chapters", "sections", may have some common elements that suggest a class hierarchy or common interface implementation.

And at the same time, enough different to be handle as different classes / objects, at all, as the requirement of "so you couldn't add a chapter to a story based on books".

When dealing conceptualy with hierarchical objects, there are several approaches of how to turn them into into code, each one suits better to a particular situation.

1. Class Composition

There is a class or prototype for each concept, they may be related or not by inheritance or interfaces. There are internal collections of the elements, and their operations can be restricted, by methods.

// this one can be optional, not required,
// replaced by several parent classes,
// or replaced by interfaces

public class LibraryRootClassMaybe {
  // members here
}

public class BookText extends LibraryRootClassMaybe {
  // members here
} // class BookText

public class BookSection extends LibraryRootClassMaybe {
    // element collection should not be public
  List BookTexts;

  public Book() {
    this.BookTexts = new ArrayList();
  }

  public void addBookTest(BookText Item) {
    // validation and casting from object to BookText
  }

  // members here
} // class BookSection

public class BookChapter extends LibraryRootClassMaybe {
    // element collection should not be public
  List BookSections;

  public Book() {
    this.BookSections = new ArrayList();
  }

  public void addBookTest(BookSection Item) {
    // validation and casting from object to BookSection
  }

  // members here
} // class BookChapter

public class Book extends LibraryRootClassMaybe {
    // element collection should not be public
  List BookChapters;

  public Book() {
    this.BookChapters = new ArrayList();
  }

  public void addBookTest(BookText Item) {
    // validation and casting from object to BookText
  }

  // members here
} // class Book

These approach is good when there are not many different classes, maybe 5.

2. The Tree Design Pattern.

These one applies when all elements will be equal if not similar, usually same class or interface, usually a lot of items.

These one does not apply to your case, but, I had to mention, to apply better.

Usually, a tree / hierarchical collection class, its used. It could be a subclass of a generic / template tree collection, or a subclass of a base tre collection, that is intended to be replaced by child classes with particular members.

public class FileSystemRootClass {

  public bool AmISystemRoot() {
    // more
  }

  public bool AmIAFolder() {
    // more
  }

  public bool AmIAFile() {
    // more
  }

  public void addSystemRoot(string FileSystemName) {
    // more
  }

  public void addFolder(string FileSystemName) {
    // more
  }

  public void addFile(string FileSystemName) {
    // more
  }

  // members here
}

3. The Hybrid.

These one is a combination of the previous two, its used when there is a lot of related items, its more complex, may use or not the Factory & Abstract Factory Patterns, and its more common example are visual controls & widgets libraries.

import java.util.*;
public class WidgetsExample {
  public static void main(String[] args) {
    TreeSet <Widget> FormControls = new TreeSet<Widget>();

    TextBoxWidget TextBox = new TextBoxWidget();
    FormControls.add(TextBoxWidget);

    ListBoxWidget ListBox = new ListBoxWidget();
    FormControls.add(TextBoxWidget);

    ButtonWidget Button = new ButtonWidget();
    FormControls.add(Button);
} // class WidgetsExample

You may notice that I didn't use the "factory pattern" & "abstract factory", due to require more code.

Good Luck.

like image 101
umlcat Avatar answered Oct 25 '25 12:10

umlcat


Good OO design starts with thinking about Use Cases and not class hierarchies. This is a common mistake and tends to produce over-complicated designs.

First consider what you are building and write out a problem statement a description of the problem you are solving using English prose in the language of the problem domain.

Then consider making a mockup if the product is a UI.

Then you can start writing out use cases and start thinking about how objects will interact with each other.

It's called Object-oriented programming, not Class-oriented programming. Classes are the specification in code to manage/create/run all the objects in the system. I'd be thinking about objects and what they are doing. Classes are simply an implementation detail.

If your goal is to perform operations on hierarchies, you might want to consider using the Composite pattern. You could do something like have a Story object that can contain a list of Story objects. Each Story object would also have it's own type (book-collection,book,chapter,sub-chapter,paragraph,essay), and it's own attributes and methods (depending on your use cases).