1

I am trying to reduce duplicates of Book objects using Flyweight design pattern but got stuck at some point.

For example, assuming that there is a book class which contains some variables such as bookName, published_date and Langauge, and someone creates a book instance:

bookName: ABC // published_date: 17-05-2020 // Langauge: English.

What I am trying to do is, when he clones the same book instance above, I want to reduce the duplicates.

But, when I searched up for the flyweight pattern, they all get String or Integer as an intrinsic value / key.

Example:

class CoffeeFlavorFactory {

  private Map<String, CoffeeFlavor> flavors = new HashMap<String, CoffeeFlavor>();
   CoffeeFlavor getCoffeeFlavor(String flavorName) {
      CoffeeFlavor flavor = flavors.get(flavorName);
      if (flavor == null) { 
          flavor = new CoffeeFlavor(flavorName);
          flavors.put(flavorName, flavor);
      }
      return flavor;
 }

The above code gets String flavorName as an intrinsic value.

What I want to ask is, is there any way to get the Book object as an intrinsic value and use the flyweight pattern?

Thanks in advance!

  • The flyweight applies to immutable values. If no 2 books will share the same name, then you can assume the date and language will be the same, and you can cache based on the name of the book alone. If you plan to have the same book with different dates, form an `int` by combining the `hashCode()` of the specified values. You don't need to account for all state if, by design, all other states will match as long as one of the states match (in this case, the name). – Vince May 17 '20 at 05:41
  • That's a good point Vince. I wasn't accounting for one book instance with always the same publishing date. But in reality a book might come in a second and third volume. The title will definitely depend on the language. So if the title will include book title "volume X" then your solution is enough. If not then there might be several publishing dates for the same book title. – Michael May 17 '20 at 05:50
  • So do you mean that, for this case: Book1 = bookName: ABC // published_date: 17-05-2020 // Langauge: English. Book2 = Book1.clone() I just can use the variable 'name' as an intrinsic value for flyweight pattern?? – helpmefromjava May 17 '20 at 05:58
  • @Michael In that case, every object supplies a `hashCode()`, so creating a new hash code based on the hash codes of the input would result in an `int` which he can use as the key for his cache entries. For example, `int key = Objects.hash(name, date)` – Vince May 17 '20 at 05:59
  • @helpmefromjava Yes, but only if your system is designed that way. If we were to cache `String`, such as `"hi"`, we would simply compare the `char` values. Even though `String` has a `length` property, we don't need to account for it in the flyweight system. But this would only work if `"hi"` would always result in a length of 2. If your design ensured the book "ABC" will always have a release date of 17-05-2020, and this same rule will apply to other books, you don't need to include the date in your flyweight design. – Vince May 17 '20 at 06:02
  • Oh I see. By the way, could you please have a look at this link? https://stackoverflow.com/questions/61789699/reduce-the-memory-usage-of-my-program-in-java-using-design-patterns Are we also allowed to use the variable, "name" in ReportImpl class as an intrinsic value for flyweight? – helpmefromjava May 17 '20 at 06:06
  • @helpmefromjav Yes, I already saw that post. Same rules apply, and I think that's what your professor wants you to realize. Although there are many arrays, if those values depend on the name (as in, the values in the array will be the same if the name is the same), then you can just use the name alone. – Vince May 17 '20 at 06:16
  • Thank you soooo much Vince! As a final question, for the post I linked, should I use Objects.hash(String name, double commission..., double[] and etc...) as an intrinsic value? or should I just use the variable, "name" as an intrinsic value? – helpmefromjava May 17 '20 at 06:20
  • @helpmefromjava Nope. That's only if you need to build 1 intrinsic value from many other values. But since you can just use `name`, you already have your intrinsic value. I'll write a comment on that post. – Vince May 17 '20 at 06:23
  • um... in this post: https://stackoverflow.com/questions/61789699/reduce-the-memory-usage-of-my-program-in-java-using-design-patterns As you can see in ReportDatabase class, there is a method called getReportData() which stores ramdom,nextDouble() elements in double[500000] array. And in getTestReports() method in ReportDatabase class, it clones each of the double[] array variables. Thinking of this situation, we can still use 'name' variable as intrinsic value for flyweight? Wouldn't Object.hash() be more appropriate approach for it? – helpmefromjava May 17 '20 at 06:30
  • @helpmefromjava Reply to the comments on that post, since this is no longer related to this post. I did find a difference that would justify `Objects.hash` opposed to just the name. – Vince May 17 '20 at 06:46
  • I cannot write a comment on that post since it is required for me to have 50 reputations to do so... So as u mentioned, I decided to use Objects.hash. By the way, for https://stackoverflow.com/questions/61789699/reduce-the-memory-usage-of-my-program-in-java-using-design-patterns, is flyweight the only way to decrease the RAM usage? What I thought is to cache each doulbe[] arrays in ReportImpl class (decreasing the size double[500000] to half). Would it be okay? (If you want, I can definitely post another question related to this question!) – helpmefromjava May 17 '20 at 06:54

1 Answers1

0

your problem doesn't sound like the intented usage scenario for the flyweight pattern which is for a big number of objects (build with repeating attributes/child objects) to "outsource" the repeatingly needed attributes/child objects to a central memory structure and then when a certain main object from your collection of objects is used to rebuild it by referencing the "outsourced" objects. (check here enter link description here
In you example you would outsource publishDate and Language objects if they were objects.

What I understood you want to do is simply preventing the creation of a duplicate if there already is an instance of that same book registered. The "same book" is currently identified by three attributes (bookName, bookPublishingDate, bookLanguage).

You can do this with your approach only the key in the hashmap should be aggregated out of all relevant attributes of the book.

Like

String bookSignature = bookName+bookPublishingDate.toString()+bookLanguage;

The creation of the String can be done with a StringBuilder if you want to save memory.

Michael
  • 131
  • 5
  • how about this question? https://stackoverflow.com/questions/61770737/flyweight-pattern-with-no-intrinsic-values is flyweight appropriate to be used for this question? – helpmefromjava May 17 '20 at 05:19
  • how would you change the reference of bookSignature variable for the question I linked? – helpmefromjava May 17 '20 at 05:27
  • I think the class in the reference would qualify if and only if there is a high probability that the exact double[] values are reappear often. Your case would qualify sooner. You can use the pattern to build up the book objects as language and publishing date are pretty much reappearing. But that would not solve identifying dublicates. – Michael May 17 '20 at 05:27
  • Reread your question and it says you want to reduce the object. You don't want to prevent them. So you want to allow them but reduce the size by reusing publishing date and language? – Michael May 17 '20 at 05:31
  • Use the Hashmap as described to maintain the first appearance of a book. Meaning search by the signature. If you get null then add that book with the signature as original. If you get a book back use that original books attributes in the duplicate class. Problem: language and publishing date are used much more often spread over several books. Solution to save memory could be to maintain separate hasmaps for the values of publishing date and language. – Michael May 17 '20 at 05:36
  • I did as what you just said, but assuming that there is another double[] variable just like the post I linked, not really sure what signature I should use. – helpmefromjava May 17 '20 at 05:46
  • "*your problem doesn't sound like the intented usage scenario for the flyweight pattern which is for a big number of objects*" - His problem could involve large number of object requests. Maybe he intends to return collection of `Book` objects every time a client queries his database of books, and there could be tens of thousands of clients searching for books. – Vince May 17 '20 at 05:47
  • `String bookSignature = bookName+bookPublishingDate.toString()+bookLanguage` would be the correct approach, if all state *must* be accounted for. The more optimal way to implement that would be to use a hash code instead of the signature: `int signature = Objects.hash(bookName, bookPublishingDate, bookLanguage)`. Either way, what you suggested would work as well (with a few caveats) – Vince May 17 '20 at 06:08
  • Also wanted to say, welcome back. Noticed you haven't posted since 2014. Usually I don't make comments like this, but good to see a returning member :) Don't let little hiccups demotivate you from answering. If you check out my early answers, they were really bad ;) Hope you continue posting Q&As! Other than tossing flyweight in the trash can, the approach mentioned is on the right track. – Vince May 17 '20 at 06:14
  • Thank you for the nice and motivating comment, Vince :-). Work lead a different path in the past. Now I am again more into software engineering and programming so wanted to help and learn in that community. – Michael May 17 '20 at 08:14
  • @helpmefromjava: I think you should mark Vince answer as correct only he hasn't posted his own... Vince: Maybe you want to rephrase your latest comment as an answer? – Michael May 17 '20 at 08:17
  • @Michael Edit your answer to include the information, and I wouldn't mind upvoting. I'm definitely not here for the reputation; would rather see others adapting :) I very much appreciate your want for credits to go where "deserved", but I feel you understood it enough to be able to formulate your own answer and earn for the effort you put in. This one is all yours :D – Vince Jun 03 '20 at 19:28