Java program design question - java

I'm trying to come up with a simple way of organizing some objects, in terms of what classes to create. Let's say I'm trying to keep track of books. A book can fall under a number of different genres and subgenres. I want to be able to recognize a book as one book and yet have it fall under these different categories. I have a genre class which keeps track of all the subgenres, and a subgenre class which has all of the books in it. I want the book to know all of the genre and subgenres that it falls under. I also want to keep track of some statistics (reviews, comments, number of times read, etc.) based on genre and subgenre and then be able to aggregate them to get numbers for the entire book. In this way, a user could select a book and know, each genre/subgenre that the book belongs to, and soem statistics about that book for each category
What are some ideas for how I can design this?
My thought was to have each Book define a class called BookGroup, and the BookGroup would contain the Genre and Subgenre, along with any relevant information for that category (assuming that subgenres can only belong to one genre). Then in the Book class I would keep a set of bookgroups that the book belongs in. I can add up stats from all the different bookgroups. The only thing I don't like about this is that I feel like a BookGroup should contain Books, not the other way around.
Any other ideas?
Thanks!
Edit:
All you guys gave really good tips. I think for simplicity reasons, I might do something like this for now:
class Book
{
Genre myGenre;
SubGenre mySubGenre;
String myTitle;
}
class Library
{
Map<String,Set<Book>> allBooks = new HashMap<String,Set<Book>>();
//where allBooks contains a mapping from book title, to all of the book objects which actually represent the same book but may contain different information related to their specific genre/subgenre
}

I'd imagine you would want your classes to look something like this:
public class Book
{
String name;
List<Review> reviews;
Set<Genre> genres;
public Book(String name, Set<Genre> genres){}
}
public class Genre
{
String name;
Set<Book> books;
public Genre(String name, Set<Book> books){}
}
I am making an assumption here that you will be utilizing a database, in turn you would have a DAO to query on all known books that match a criteria and subsequently perform CRUD operations across the datasets. I feel a bit off by suggesting that the Genre constructor takes a Set of Book objects, but at the moment I can't think of another way to do this right now.

So, the problem is to do with inverse relationships, really. It's quite difficult to avoid this and maintain efficiency. A relational database sidesteps this issue by optimising in the background, using efficient query operations, and never storing the inverse relationship in the first place.
If you use a relational database in the background, you can create methods that get the book groups using a relational query without ever storing the information in Java.

I would just make two enums, one BookGenre = {scifi, novel, ...} and similar for subgenres. When creating a new Book object, add a reference to the Book object to some list which keeps track of all scifi book, etc ( i.e. make an EnumMap> which maps each genre to a list of books ); in this way you can easily access all the books of a genre.

There have been good suggestions from the other posters, but your original idea might work as well. The biggest problem for you, if I understand you correctly, appears to be one of naming: your 'BookGroup' is not really a grouping as such, but a descriptor of which group (genre/subgenre) it belongs to plus associated statistics. If you renamed it to e.g. 'BookGenreStatistics', the question of who contains what would go away.

I think you want collections pointing to each other. And when adding a book to a changre you would also add the changre to the book. Then just iterate as needed to obtain what you wanted. A changre and a sub changre should really be the same class, no need to have different classes here.
An alternative to this would be not to have references in a book to what changres it belongs to, instead if you need to know you would have to iterate through all changres and see if the book is in them. Depends on how many changres there are and how usual it is for a book to belong to a changre. Let's say if most changres have over half of all the books in them. The obvious third option is not to have books in changres, in that case you would have to iterate through the books to obtain the changres, the question is if most books belong to almost all changres, or if changres are unusual and only contain few books.
If you chose option number one, then a changre would be able to contain books and other changres, and a book would be able to contain changres but not other books. Sounds similar doesn't it? Well, it is, a changre and a book is the same thing, well, almost. The main difference is how you use them. Imagine a tree where the changres on top point down to subchangres and so forth, then they in turn point down to books who in turn point back up to the subchangres they're part of. Then in order to find all books in a changre for instance you would just have to traverse the tree from root up, except when you're at a book you stop. If a book can belong to several changres (yes, it can, right?), then you just need a loop variable in the book that's set when iterating and if the book is reached a second time you know because the variable has already been set.
For instance finding all the books in a changre:
1. Construct collection object that is to hold the result.
2. (in subclass changre) Iterate through all changres and books (they might be stored in the same collection object)
2. (same method as above, but in subclass book) Check if iteration field is set, if so just return, else add this to the result collection object.
3. Unset iteration field in all books of the result collection object to make it possible to redo from step one. (the alternative to having such an iteration field is of course use a collection that doesn't matter if you put in duplicates)
-Done, a book simply instead of iterating through the changres it has (like a changre does) knows that it has to add itself to the result.
Now that I think about it I think there's a tool that automatically generates code where you can specify things like a changre can have books and so on, and then to find all book reviews in a changre you can specify to traverse from the changre, pass at most one book on your path through the graph, and end in a review, and then agregate the results, and it generates code that does that. I don't remember the name or what language it was, but I think code like this can be generated from only a few lines, but of course writing it yourself shouldn't hurt either.

Related

Gather list of #PlanningEntity or #PlanningVariable when evaluating constrains in filter()

I would like to gather a list of #PlanningEntity or #PlanningVariable in order to use it in a constraint. I have an airline problem where I have a Seat and it gets assigned a Passenger based on a preference and weight (basically a Bid). I want the top passengers with highest Bids assigned to be rewarded for their assigned Seat.
I have tried groupBy but it returns a list() with one value, the current Passenger
constraintFactory
.forEach(Passenger.class)
.groupBy(Function.identity(), ConstraintCollectors.toList())
.join(Seat.class, Joiners.equal( (pass, passList) -> pass, Seat::getPassanger))
//for each passenger for each seat make sure the passenger was the highest bid
.filter((pass, passList, seat) -> {... }
In my example I want the passList to be the full list of Passengers. I'm not sure if this even possible with the API. I can always "hack" it and get the list other ways in my application. Thanks for any info.
This is due to a misunderstanding of how groupBy(...) works. The first argument specifies the group key, and the second argument is the function that should be used on all members of the group. Since the first argument is Passenger, and the stream contains nothing but Passenger, each group will have exactly one member (that one Passenger instance), and therefore so will the list.
What you're trying to do is:
constraintFactory
.forEach(Passenger.class)
.groupBy(ConstraintCollectors.toList())
This way, there is only one group, and that group contains all of the Passenger instances. However, I want to stress that you should not do this either.
The power (and speed) of Constraint Streams comes from the fact that it can process data incrementally. When a Passenger changes, we know we should only re-evaluate those constraints where the Passenger class is involved, and specifically where the given instance of Passenger is involved. Therefore, instead of processing possibly thousands, millions of passengers, we will only process those that were added, removed, or changed.
However, when you collect to a list, all of that goes away - from that moment on, all we have is a list. And none of the operations on the contents of that list will happen incrementally. In fact, your own processing functions will be written so that you operate on the list, and not on the individual changed elements. Therefore, doing something like this kills your performance.
I understand why people do this. Imperative programming, and more importantly imperative thinking, is easier. Thinking in Constraint Streams is harder, and takes some getting used to. Still, I advise you to try to think about doing this in an incremental way, and if you can't figure it out, define your constraint precisely in another StackOverflow question, and maybe someone will be able to help you.

Data structure for fast searching of custom object using its attributes (fields) in Java

I have abstract super class and some sub classes. My question is how is the best way to keep objects of those classes so I can easily find them using all the different parameters.
For example if I want to look up with resourceCode (every object is with unique resource code) I can use HashMap with key value resourceCode. But what happens if I want to look up with genre - there are many games with the same genre so I will get all those games. My first idea was with ArrayList of those objects, but isn’t it too slow if we have 1 000 000 games (about 1 000 000 operations).
My other idea is to have a HashTable with key value the product code. Complexity of the search is constant. After that I create that many HashSets as I have fields in the classes and for each field I get the productCode/product Codes of the objects, that are in the HashSet under that certain filed (for example game promoter). With those unique codes I can get everything I want from the HashTable. Is this a good idea? It seems there will be needed a lot of space for the date to be stored, but it will be fast.
So my question is what Data Structure should I use so I can implement fast finding of custom object, searching by its attributes (fields)
Please see the attachment: Classes Example
Thank you in advanced.
Stefan Stefanov
You can use Sorted or Ordered data structures to optimize search complexity.
You can introduce your own search index for custom data.
But it is better to use database or search engine.
Have a look at Elasticsearch, Apache Solr, PostgreSQL
It sounds like most of your fields can be mapped to a string (name, genre, promoter, description, year of release, ...). You could put all these strings in a single large index that maps each keyword to all objects that contain the word in any of their fields. Then if you search for certain keywords it will return a list of all entries that contain that word. For example searching for 'mine' should return 'minecraft' (because of title), as well as all mine craft clones (having 'minecraft-like' as genre) and all games that use the word 'mine' in the 'info text' field.
You can code this yourself, but I suppose some fulltext indexer, such as Lucene may be useful. I haven't used Lucene myself, but I suppose it would also allow you to search for multiple keyword at once, even if they occur in different fields.
This is not a very appealing answer.
Start with a database. Maybe an embedded database (like h2database).
Easy set of fixed develop/test data; can be easily changed. (The database dump.)
. Too many indices (hash maps) harm
Developing and optimizing queries is easier (declarative) than with data structures
Database tables are less coupled than data structures with help structures (maps)
The resulting system is far less complex and better scalable
After development has stabilized the set of queries, you can think of doing away of the DB part. Use at least a two tier separation of database and the classes.
Then you might find a stable and best fitting data model.
Should you still intend to do it all with pure objects, then work them out in detail as design documentation before you start programming. Example stories, and how one solves them.

How to implement a simple scenario the OO way

After starting to read a book on OO programming, I am attempting to make my android app more OO. However I am stumped on a simple scenario.
I have a Book object, which can have many say Chapter objects. I also have a search function which searches across multiple books, 97 of them. I end up with many Chapter objects from the Sqlite table.
I felt that it would be useful to the user to be able to see the title of the book on each result, otherwise it might be confusing if there are say two "chapter 5" results.
For that to happen, I need the book title. Should I make it part of my chapter object, like :
chapter.getBookTitle()
Which kind of does not seem right, as I have glued the book name onto a chapter... The alternative is to instantiate a book object for each chapter and somehow reference it, which has its own problems including in android with regards to not being able to pass a reference to an in-memory object to another activity.
Also a book may have many other chapters which were not results in the search, and it may seem like they would return if I was to just instantiate the book.
What is the correct OO solution to this seemingly simple issue? Is it just a matter of learning when not to be dogmatic about the whole OO thing?
More Info:
I am using FTS4 in Sqlite, which accounts for over half of my actual DB size of 80mb. What I am storing is text from 97 books, with chapters in 4 languages. So my FTS at the moment stores:
ChapterId, ChapterNo (withinBook), Lang1, Lang2, Lang3, Lang4, Tags, Notes
The searching is very fast, I retrieve only 50 results. I match any column with a string term, and not one column in particular. So if I type "apple" it will search all the fields above.
Currently as part of my FTS query I am join a join onto Book, fetching the BookId, I later use that to get me the title of the book. However its all in a procedural like style, with no regard to where the information "belongs".
I need the title so I can display it in the results, just for user convenience.
It works well, however I am wanting similar performance or slightly less but with an OO approach as I think that will make more sense to me when I come back to this project after a long pause.
The Chapter object should have reference to the book it came from so I would suggest something like
chapter.getBook().getTitle();
Your database table structure should have a books table and a chapters table with columns like:
books
id
book specific info
etc
chapters
id
book_id
chapter specific info
etc
Then to reduce the number of queries use a join table in your search query.
The approach I would take is: when reading the chapters from the database, instead of a collection of chapters, use a collection of books. This will have your chapters organised into books and you'll be able to use information from both classes to present the information to the user (you can even present it in a hierarchical way easily when using this approach).
You might implement your class model by composition, having the book object have a map of chapter objects contained within it (map chapter number to chapter object). Your search function could be given a list of books into which to search by asking each book to search its chapters. The book object would then iterate over each chapter, invoking the chapter.search() function to look for the desired key and return some kind of index into the chapter. The book's search() would then return some data type which could combine a reference to the book and some way to reference the data that it found for the search. The reference to the book could be used to get the name of the book object that is associated with the collection of chapter search hits.

Java linked list within a linked list

I am trying to do a little project I found online which is creating a Library Catalog of books and users.
I created 3 classes - Book, User, Manager. Manager has all the methods of checking out books, updating late fees, returning books etc. All these methods take place on a single user.
So if a user wants to check out a book, the manager calls the checkoutBook method on that user along with the book/s and checks them out. One problem I ran into was with late books. I want to be able to tie multiple late books to a single user. Using two separate lists here is too much of a hassle.
So I opted for a linked list within a linked list. But how exactly do I insert an element into the initial list and link it to the second list?
I.e. here is my code:
private LinkedList<User> userList = new LinkedList<User>();
private LinkedList<LinkedList<Book>> lateList = new LinkedList<LinkedList<Book>>();
userList is simply a list of whoever has checked out a book. In my lateList, I want to be able to insert a user within the first list, and a number of late books in the second list tied to that particular user.
How would I go about doing this? I tried to find some info online but it usually refers to placing a linked list within another linked list via the add method. Is there a good way of doing this or am I better off designing a separate class (or user a better data structure) to do this?
What I would do is, instead of having a linked list of linked lists of books, just have a linked list of late books within your user class. Then you can add methods to add/delete books from the list as you see fit. This approach makes more sense to me because the late books are essentially owned by the user, and this way you don't have to keep track of a user's late books by matching indices and tying them to another linked list.

Should I use a nested enum?

Say I need a data structure in Java involving one set of categories, each with one set of subcategories. For example, let's say the main category is 'brand' (like, of a product) and the subcategory is 'product'. I want to be able to map the combination of brand+product to a piece of data e.g. a price.
I'd like to use an enum type for both 'brand' and 'product' if they were on their own, because
Brand+product has only a small, single piece of data tied to it (the price)
I need to refer to them many times throughout a reasonably large program, so the chance that I'll mistype any string literal keys I assign to them is basically one.
However, the number of brands/products is too large to have a single enum for each brand/product combination (around twenty brands each with ten products and a good chance of adding more later). I'd like to be able to use the structure like this:
getPrice(APPLE.IPOD)
getPrice(APPLE.MACBOOK)
getPrice(HERSHEYS.PEANUT_BUTTER_CUPS)
Should I use some sort of nested enum? If so, how would that be implemented?
Bonus information: I've spent a bit of time googling 'java nested enum' but haven't come up with anything. The problem with structures like the first one in the ticked answer here or thelosts's answer here is that I have too many categories all exhibiting the same behavior to write out very similar enum definitions so many times.
I wouldn't use an enum for this.
I would suggest you load this information from a file or database. Java is not a good place for storing large amounts of data.
You could add a getter and setter to the Brand enum that allows setting a Product enum, but that will not enforce that a Product is actually manufactured by that Brand. Besides, there is ever only one instance of each enum value -- so you could never have APPLE.IPOD and APPLE.IPAD. You either need a single enum type that represents the Cartesian product, or you need to load your values from a data store like Peter Lawrey suggests.

Categories

Resources