I'm doing a basic exercise of object-oriented design for a simple use case: A Book can be tagged with many Tags.
I have many solutions, and I would like your input on which is better in term of OOD principles and maintanability.
Option 1
public class Book {
private String title;
//... other attributes
private List<Tag> tags;
}
The thing that bothers me is that we mixed core attributes of a Book with additional categorization or search data. I may have in the future a requirement where certain Books can't be tagged. In the future, the Book class can become bloated when I add more responsabilities: category, list of users that read it, ratings...
Option 2
public class TaggedBook extends Book {
private Book book;
private List<Tag> tags;
}
I think this is similar to the Decorator pattern, but I don't see it fit here because I'm not extending behavior.
Option 3
Decouple Books and Tags comnpletely, and use a service to retrieve Tags from a book (given each Book has a unique identifier)
List<Tag> TagService.getTags(Book book)
However, I don't find this solution very elegant (is it?), and I may have to send two queries: one to retrieve the book, the other for the tags.
I am planning on applying the best options to other requirements: A Book has a rating, a Book can be categorized...
I'm also planning on using a DMS to store Books and Tags objects. Since it's not a relations database, its schema will likely correspond to the class design.
Thank you
All three options can be valid and good choices for your class design. It all depends on the complete context/requirements. The requirement you listed are very likely not enough to make the "right" decision. For example, if your application is rather book centric and tags do not need to evolve or be authored independently from books, option 3 would probably introduce unnecessary complexity. If you design a public API that acts as a facade around your actual logic you still might go for option 1 or 2 even though internally both Book
and Tag
are totally decoupled aggregate roots. Scalability, performance, extensibilty ... those are all possible requirements that you need to balance and that will influence your design.
If you are looking for a good formalized methodology and guidance for class design for enterprise applications, I'd suggest you look into Domain Driven Design.
Also, do not design you classes for unknown future requirements. This will also again add useless complexity (think: cost). Just make sure you have enough unit test that cover your back when you need to refactor for new requirements.
The concept of decorator pattern fits well in your case.But I think strategy pattern is more useful and effective in you case.If you don't know about strategy pattern then Take a look on This.It will give you a good idea on strategy pattern.If you need more suggestion or have any query then ask in comment. Thank you All the best..
If Books are not the only Entity in your Model that can be tagged. I'll go with this interface:
public interface Taggeable {
public List<Tag> getTags();
public void setTags (List<Tag> tags)
}
And
public class Book implements Taggeable {
//Book attributes and methods
The kinds of Books/Entities that can be Tagged only need to implement this interface. That way, you can have Book objects that allow tagging and others that doesn't. Also, the tagging mechanism can be used with other Objects of your model.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With