Problem

Design the data structures for an online book reader system.

Solution

We will have 2 simple classes - book and user.

Book.java

public class Book {

	private long id;
	private String title;
	private long authorId;
	
	public long getID() {
		return ID;
	}

	public Book(long id, String title, long authorId) {
		// ...
	}
}

User Class


public class User {

	private long ID;

	private String username;
	private String email;
	private int accountType;

	public long getID() {
		return ID;
	}

	public Book searchLibrary(long id) {
		return Book.find(id);
	}

	public void renewMembership() {}
}

Now we need an management system, which can manage them. The users and books have m:n relationship between them, i.e. multiple users can have same book and same user can have multiple books. To solve this we will have new table in database, which will have book to user mapping, with foreign key reference to user and book id, both being the composite key.

The reader system will look like this.

Managing books

public class Books {

	private Set<Book> books;

	public void addBook(long iD, String details) {
		books.add(new Book(iD, details));
	}

	public void update() {}

	public void delete(Book b) {
		books.remove(b);
	}

	public Book find(long id) {
		for (Book b: books)
			if (b.getID() == id)
				return b;
		return null;
	}
}

Managing users

public class Users {

	private Set<User> users;

	public Book searchLibrary(long id) {
		return Book.find(id);
	}

	public void renewMembership() {}

	public static User find(long ID) {
		for (User u: users) {
			if (u.getID() == ID)
				return u;
		}

		return null;
	}

	public void addUser(long ID, String details,
		int accountType) {
		users.add(new User(ID, details, accountType));
	}

	public User(long iD, String details, int accountType) {}
}

Now we need the 1:1 mapping between book and user, which is managed by Book User, and online reader finally manages everything :

public class BookUsers {

	private HashMap < Book, Set<User>> bookUsers;

	private HashMap < User, Set<Book>> userBooks;

	private void addUserToBookUserList(Book b, User u) {
		if (bookUsers.containsKey(b)) {
			Set<User> users = bookUsers.getValue(b);
			users.add(u);
		} else {
			bookUsers.add(b, new HashMap<User>() {
				u
			});
		}
	}

	private void addBookToUserBookList(Book b, User u) {
		if (userBooks.containsKey(u)) {
			Set<Book> books = userBooks.getValue(u);
			books.add(b);
		} else {
			userBooks.add(u, new HashMap<Book>() {
				b
			});
		}
	}

	public void assignBookToUser(Book b, User u) {
		addUserToBookUserList(b, u);
		addBookToUserBookList(b, u);

	}
}


public class OnlineReaderSystem {

	private Books books;

	private Users users;

	private BookUsers bookUsers;

	private HashMap < Book, Set<User>> bookUsers;

	private HashMap < User, Set<Book>> userBooks;

	public void assignBookToUser() {
		bookUsers.assignBookToUser(b, u);

	}

	public OnlineReaderSystem(Books books, Users users) {}

	public void listenRequest() {}

	public Book searchBook(long ID) {
		return books.find(ID);
	}

	public User searchUser(long ID) {
		return users.find(ID);
	}

	public void display() {}

}

ER Diagram

Unfortunately, BookUser will change when we take into account db relational model, as we dont have to keep things in-memory. But this is what I got. Here is Crowe’s notation for entity relationship :

 erDiagram
     BOOK ||--o{ BOOK_USER : included_in
     BOOK {
         int id PK "Primary Key"
         string title "Book title"
         string author "Book author"
     }
     USER ||--o{ BOOK_USER : has
     USER {
         int id PK "Primary Key"
         string username "Unique username"
         string email "User's email address"
     }
     BOOK_USER {
         int user_id FK "Foreign Key to USER"
         int book_id FK "Foreign Key to BOOK"
         datetime last_accessed "Timestamp of last access"
         int current_page "User's current page"
     }