This article is an excerpt from my book about Data-Oriented Programming.

More excerpts are available on my blog.


In the previous part, we presented a possible OO design for a library management system.

In this part, we continue our exploration of the tendency of OO systems to be complex.

Dave's reaction to your design

Dave follows you to your desk and you show him your piece of art: the UML diagram.

"Wow! Such a detailed class diagram." Dave is really excited.

"Yeah. It’s pretty neat." You reply proudly.

"The thing is that I can never remember the meaning of each arrow" Dave admits.

"There are 4 types of arrows in my class diagram: composition, association, inheritance and usage", you reply with a feeling of superiority.

"What’s the difference between composition and association?", Dave asks.

You google "composition vs association" and you read loudly to Dave:

"It’s all about whether the objects can live one without each other: with composition, when one object dies, the other one dies also, while in an association relation, each object has an independent life."

In my class diagram, there are two kinds of composition relation, symbolized by an arrow with a plain diamond at one edge, and an optional star at the other edge:

  1. A Library owns a Catalog. That’s a one-to-one composition relation: if a Library object dies, then its Catalog object dies with it.

  2. A Library owns many Members. That’s a one-to-many composition relation: if a Library object dies, then all its Member objects die with it.

composition
Figure 1. Two kinds of composition: one to one and one to many. In both cases, when an object dies, the composed object dies with it.

"Do you have association relations in your diagram?" Dave asks

"Yeap. Take a look at the arrow between Book and Author. It has an empty diamond and a start at both edges: it’s a many to many association relation".

Indeed, a book can be written by multiple authors and an author can write multiplet books. Moreover, Book and Author objects can live independently.

association
Figure 2. Many to many association relation: each object lives independently

"I see also many dashed arrows in your diagram", Dave notices.

"Dashed arrows are for usage relations: when a class uses a method of another class. Consider for example, at the Librarian::blockMember() method. It calls Member::block()."

usage
Figure 3. Usage relation: a class uses a method of another class

"I see. And I guess that plain arrows - like the one between Member and User - represent inheritance."

"Absolutely"

inheritance
Figure 4. Inheritance relation: a class derives from another class

"Great! Now that I understand the meaning of each kind of arrow. "Where should I look first?" Dave asks

"I think you should start from Library."

library
Figure 5. The Library class

In terms of code, a Library object does nothing on its own, it delegates everything to objects it owns:

  1. It owns multiple Member objects

  2. It owns multiple Librarian objects

  3. It owns a single Catalog object

"Looks pretty clear to me. What’s next?"

"`Librarian` and Member who both derive from User "

user
Figure 6. Librarian and Member derive from User

The User class represents a user of the library.

  1. In terms of data members, I stick to the bare minimum: it has a id, email and password (I’ll deal with security and encryption, later).

  2. In terms of code, it can login via login()

The Member class represents a member of the library.

  1. It derives from User

  2. In terms of data members, it has nothing more than User

  3. In terms of code, it can:

    1. Checkout a book via checkout()

    2. Return a book via returnBook()

    3. Answer if it is blocked via isBlocked()

  4. It owns multiple BookLending objects

  5. It uses BookItem in order to implement checkout()

The Librarian class represents a librarian.

  1. It derives from User

  2. In terms of data members, it has nothing more than User

  3. In terms of code, it can:

    1. Block and unblock a Member

    2. List the book lendings of a member via getBookLendings()

    3. Add book items to the library via addBookItem()

  4. It uses Member in order to implement blockMember(), UnblockMember() and getBookLendings()

  5. It uses BookItem in order to implement checkout()

  6. It uses BookLending in order to implement getBookLendings()

"What class should I look at now?"

"The Catalog class who is responsible for the management of the books."

catalog
Figure 7. The Catalog class
In terms of code, a Catalog object can:
  1. Search books via search()

  2. Add book items to the library via addBookItem()

    1. It owns multiple Book objects

    2. It uses Librarian in order to implement addBookItem

"Then we have the Book class"

book
Figure 8. The Book class
  1. In terms data members, we stick to the bare minimum: it has a id, and a title

  2. It is associated with multiple Author objects (A book might have multiple authors)

  3. It owns multiple BookItem objects, one for each copy of the book

"What’s a BookItem?"

"The BookItem class represents a book copy. A book could have many copies."

  1. In terms data members, we stick to the bare minimum: it has a id, and a rackId (for its physical location in the library)

  2. In terms of code, it can be checked out via checkout()

  3. It owns multiple BookLending objects, one for each time the book is lent

"Wow! That’s amazing" Dave compliments you. "I didn’t know people were really spending time to write down their design in such details, before coding."

"I always do that. It saves me lots of coding errors", you reply proudly.

"When will you start coding?" Dave asks

"When I finish my coffee".

You look at your coffee mug and it’s full (and cold). You were so excited to show your class diagram to Dave that you forgot to drink your coffee.

Go and make yourself another cup of coffee before you move to the next part.

This article is an excerpt from my book about Data-Oriented Programming.

More excerpts are available on my blog.