Most of you have probably discovered that the interface given to us by Sun is simply not rich enough to support certain needed operations. For me, these operations include retrieving metadata and saving cached records.
I am unsure as to how I should enrich DB. Generally, it's good practice to program to interfaces, so I thought of putting these two operations into a new interface which extends DB, and which Data implements. However, I feel uncomfortable with this design. For one, such an interface is rather artificial and I had a difficult time naming it. I ended up naming it "ExtendedDB" which is quite awkward. Furthermore, I am unsure whether or not the specifications allow me to implement DB indirectly (through ExtendedDB).
Thus, at the moment, I see several options open to me:
1. Keep the awkward "ExtendedDB" and explain it in choices.txt
2. Enrich Data itself with the needed operations. This gets rid of the awkwardness, but then clients must directly program to the implementation type "Data", which reduces flexibility. This isn't actually a huge issue though, since the service layer encapsulates all Data operations; the loose coupling means the inflexibility is contained. I'd still feel bad doing it though.
3. Make 2 interfaces "CachedDB" and "DescriptiveDB" each of which extends DB. Data then implements both of these, forming a sort of "diamond inheritance". This gets rid of the awkwardness. However, initial instantiations of Data would still have to directly interact with the implementation type, casting it appropriately when passing it to modular regions of code. But certain other regions might need both; consequently, I would've introduced complexity without solving the issue.
4. Implement all save code as a shutdown hook in the same place where the database is initially read (for me, this is the constructor of Data; for others, this might be internal to their DAO). This greatly simplifies everything and solves all above problems (I can just use DescriptiveDB). The anonymous inner class would even have direct access to the state left behind by the read; it would be able to reuse the RandomAccessFile and know where the schema ends and where the real data begins. The big problem is that the read code is already quite long (nearly 40 lines) and the write code would be of a similar size. Since both of these must exist within the same region of code, it would greatly increase the complexity of that region; I would likely have points taken off. However, with the other 3 designs the complexity would escape this region, leaking to nearly every other region as well. Therefore, this might well be the lesser of the evils.
Roel De Nijs wrote:Creating your own interface which extends the given interface is no problem at all. Many people passed with such an approach (me being one of them).
Ok thank you! I was actually quite worried about that (any human grader would've understood, but I was afraid that that's something the auto-grader would fail people on). But options 1, 3, and 4 all involve doing exactly what you said, so which would you suggest and why?
1. That's what I did (and ExtendedDB is just a name). I believe some assignments have DBMain as interface, also a bit awkward in my opinion
2. Definitely a no-go. You should always program against an interface
3. The more interface you have, the more complex your code would be and the harder it gets for another developer to understand your design
4. I created a shutdown hook (at constructor time), but I also have a method in my custom interface to write methods to the database. This method could be used for periodic saves of the database file
Hope it helps!
Joined: Jul 29, 2011
It certainly did!
So it seems that you used a combination of 1 and 4. If you also had a method in your custom interface to write records back to the database, then I'm guessing you must've persisted at least the construction parameters through the use of fields? Do you feel that this added complexity was worth the added benefit of being able to periodically save? And did you make use of this feature, or was it more of an extensibility thing?
Howard Stark wrote:I'm guessing you must've persisted at least the construction parameters through the use of fields?
The only thing you strictly need to store in an instance member, is the path to the database file. But because I didn't want to read the complete database schema again, I also stored some other things (like start of the records section).
Howard Stark wrote:Do you feel that this added complexity was worth the added benefit of being able to periodically save? And did you make use of this feature, or was it more of an extensibility thing?
My shutdown hook just uses this extra method. I didn't add periodic saves to my application (but I did mention it in my choices.txt)