File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Cache in Data Class Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Cache in Data Class" Watch "Cache in Data Class" New topic
Author

Cache in Data Class

Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

I was reading a post here about someone who used a cache in their data class and they were worried about someone calling one of the DB interface methods before the cache was loaded. They seem to be throwing exception in the DB interface methods if the cache has not been loaded i.e. in the implementation of the methods read(), update(), delete(), create(), and find().

But surely you would make the existence of a loaded cache a class invariant i.e. it's not possible to call any of the DB interface methods on your Data class without the cache being loaded.

You'd achieve this by making your Data class a singleton and in your getInstance() static class method you would only return an instance of the Data class if the cache could be loaded. Once you get an instance of the Data class back from the getInstance() method you would know that the cache has been loaded.

So you would have two static methods in your Data class:

public static DBExtension getInstance(final String databaseLocation)

  • This method would be called when you launch the application\server for the very first time.
  • This method would firstly check if the cache is loaded, and if it is, then it should throw an Exception as the cache should not be loaded twice at runtime.


  • public static DBExtension getInstance()

  • This method would be called if you need to get a handle on Data class after you have loaded the cache.



  • You could also add in a isInitialised() method that will tell you whether the Data class has been initialised (i.e. cache has been loaded), so that you know which of the two getInstance() methods to call.

    Based on this, there should be no need to check if the cache is loaded when calling the methods of Data class such as read(), update(), delete(), create(), and find().

    There's no need because it's impossible to call these methods without the cache being loaded, as it's impossible to get an instance of the Data class if the getInstance() method failed. If the getInstance() method returns successfully then you are guaranteed that the cache is loaded.

    Init()\Exit() Methods

    The thread referenced above also mentioned exposing the Init() and Exit() methods. Where the Init() method loads the cache and the Exit() method writes the cache back to the file.

    Exposing the Init() method would not be a good approach based on my reasoning above as someone could write code that would reload your cache (with potentially different content) at runtime - you wouldn't want this to happen.

    So based on that. Surely you would make the Init() method private and call it inside your getInstance() method. You would leave your Exit() method public to allow you to initiate writing the cache back to the file from the BusinessService.


    SCJP (1.4 | 5.0), OCJP (6.0), OCMJD
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:They seem to be throwing exception in the DB interface methods if the cache has not been loaded i.e. in the implementation of the methods read(), update(), delete(), create(), and find().

    That's what I did too.

    Sean Keane wrote:So you would have two static methods in your Data class

    That's what my good buddy Roberto did. But still you would have to cope with the situation that a developer initializes the Data instance with a call to the no-parameter version of getInstance (instead of the one with the dbLocation). And I think you should also care about thread safety (preventing 2 threads initializing the cache with a different database file).

    Sean Keane wrote:You could also add in a isInitialised() method that will tell you whether the Data class has been initialised (i.e. cache has been loaded), so that you know which of the two getInstance() methods to call.

    Huh Why would you want/need this extra method? Your getInstance-method without parameters should throw an IllegalStateException when invoked if the Data class is not yet initialized, because that's a mistake of the developer (he/she should read your API more carefully and use the correct method). You don't want to end up with code like this to get a good instance.


    Sean Keane wrote:Exposing the Init() method would not be a good approach based on my reasoning above as someone could write code that would reload your cache (with potentially different content) at runtime - you wouldn't want this to happen.

    I don't agree. My init()-method is exposed as a public method and I don't see why that would not be a good approach. Someone trying to reload my cache? Not a chance: on the 1st call the data class will be initialized, following calls will have no effect at all (and that's clearly mentioned in the javadoc of this method). Also mentioning in the javadoc that this method should be called before any other method.

    Sean Keane wrote:Surely you would make the Init() method private and call it inside your getInstance() method.

    No, you won't. Because that would mean you have to change the signature of your getInstance-method and add the necessary parameters to be able to call the init-method. And that's not something you want (and that's why you have the alternative with the 2 getInstance-methods)


    SCJA, SCJP (1.4 | 5.0 | 6.0), SCJD
    http://www.javaroe.be/
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    I think my main discussion about this solution is probably going on in this thread here. But just to touch on a few things

    Roel De Nijs wrote:
    Sean Keane wrote:They seem to be throwing exception in the DB interface methods if the cache has not been loaded i.e. in the implementation of the methods read(), update(), delete(), create(), and find().

    That's what I did too.

    Sean Keane wrote:So you would have two static methods in your Data class

    That's what my good buddy Roberto did. But still you would have to cope with the situation that a developer initializes the Data instance with a call to the no-parameter version of getInstance (instead of the one with the dbLocation). And I think you should also care about thread safety (preventing 2 threads initializing the cache with a different database file).


    You are guaranteed that two threads won't attempt to load the cache simultaneously simply by making the getInstance() method synchronized, no?

    Roel De Nijs wrote:
    Sean Keane wrote:Exposing the Init() method would not be a good approach based on my reasoning above as someone could write code that would reload your cache (with potentially different content) at runtime - you wouldn't want this to happen.

    I don't agree. My init()-method is exposed as a public method and I don't see why that would not be a good approach. Someone trying to reload my cache? Not a chance: on the 1st call the data class will be initialized, following calls will have no effect at all (and that's clearly mentioned in the javadoc of this method). Also mentioning in the javadoc that this method should be called before any other method.


    If I am understanding you correctly, then subsequent calls to your init() method will have no effect and will return silently. I understand you have documented it in the JavaDoc - but that doesn't make it intuitive. It just means it was unintuitive in the code, but you documented it.

    It is far more intuitive reading the code (without having to jump off to JavaDoc) to have this:
    I can read this code and understand exactly how everything works without needing to read the JavaDoc. Thus it is more intuitive.

    Roel De Nijs wrote:
    Sean Keane wrote:Surely you would make the Init() method private and call it inside your getInstance() method.

    No, you won't. Because that would mean you have to change the signature of your getInstance-method and add the necessary parameters to be able to call the init-method. And that's not something you want (and that's why you have the alternative with the 2 getInstance-methods)


    I don't see any good reason why you wouldn't want to return an initialised instance of the Data class from the getInstance() method - what reasons were you thinking of?

    Regards changing the signature of the getInstance() method to pass in the parameters. What problem do you see with this? I can't see any. You are adding one parameter - the location of the database file.
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:You are guaranteed that two threads won't attempt to load the cache simultaneously simply by making the getInstance() method synchronized, no?

    Agreed.

    Sean Keane wrote:If I am understanding you correctly, then subsequent calls to your init() method will have no effect and will return silently. I understand you have documented it in the JavaDoc - but that doesn't make it intuitive. It just means it was unintuitive in the code, but you documented it.

    I could also have decided to throw an exception, just like you did with your getInstance(dbLoc)-method. Did you document in javadoc that multiple calls will result in an exception? Same question for using the getInstance()-method before the instance was initialised. I guess you didn't, otherwise it would make your code unintuitive too, based on your argumentation and you said in another thread your api is intuitive (so that would contradict each other). You see it as documenting something unintuitive in the code, I see it as fully documenting your API (like you also come across in other frameworks, e.g. Swing). It has nothing to do with unintuitive code, but with giving complete documentation to the developers who might use your code (so they don't have to use some decompiler to see how your code is working).

    Sean Keane wrote:I don't see any good reason why you wouldn't want to return an initialised instance of the Data class from the getInstance() method - what reasons were you thinking of?

    Because you need to alter the signature of the getInstance() method.

    Sean Keane wrote:Regards changing the signature of the getInstance() method to pass in the parameters. What problem do you see with this? I can't see any. You are adding one parameter - the location of the database file.

    In each occurence of the getInstance you'll have to provide this parameter (even if you don't need/want it). And if I follow your implementation (because I want to prevent reloads, so I throw an exception) then I can call the getInstance method just once. I could pass null as dbLocation, but then we are actually back on the 2 getInstance-methods path
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Roel De Nijs wrote:I could also have decided to throw an exception, just like you did with your getInstance(dbLoc)-method. Did you document in javadoc that multiple calls will result in an exception? Same question for using the getInstance()-method before the instance was initialised. I guess you didn't, otherwise it would make your code unintuitive too, based on your argumentation and you said in another thread your api is intuitive (so that would contradict each other). You see it as documenting something unintuitive in the code, I see it as fully documenting your API (like you also come across in other frameworks, e.g. Swing). It has nothing to do with unintuitive code, but with giving complete documentation to the developers who might use your code (so they don't have to use some decompiler to see how your code is working).


    Yes, I would document the behaviour of the getInstance method. The key difference I see is it that your method for loading the cache operates differently depending on the state of the object - if the cache is not loaded then it will be loaded with the contents of the file specified, if the cache is loaded then the request will be ignored. The user of your API has no way of telling which of the two behaviours just occurred.

    With my approach an Exception will be thrown if an attempt is made to reload the cache. This is correct. An exception should be thrown. It is an exceptional circumstance. You don't want someone to be allowed reload the cache.

    With your approach. An attempt could be made to load the cache, after it has already been loaded. Your init-method will return silently - I have no way of knowing whether the cache was loaded with the database file I specified or whether you just ignored my request.

    As a user of the API. I should be able to tell if my call to the method was carried out successfully or not. It is not possible to tell this with your approach.

    Roel De Nijs wrote:
    Sean Keane wrote:I don't see any good reason why you wouldn't want to return an initialised instance of the Data class from the getInstance() method - what reasons were you thinking of?

    Because you need to alter the signature of the getInstance() method.


    Ah, ok. So you feel because there is a general usage of a name\signature of a method in the Singleton pattern, and usually this method doesn't take an argument, that by me adding an argument it may be confusing for developers. That is why you think it is a bad idea?

    I don't think that is a very strong argument for not adding a parameter to the getInstance-method.

    Roel De Nijs wrote:
    Sean Keane wrote:Regards changing the signature of the getInstance() method to pass in the parameters. What problem do you see with this? I can't see any. You are adding one parameter - the location of the database file.

    In each occurence of the getInstance you'll have to provide this parameter (even if you don't need/want it). And if I follow your implementation (because I want to prevent reloads, so I throw an exception) then I can call the getInstance method just once. I could pass null as dbLocation, but then we are actually back on the 2 getInstance-methods path


    Yep, and what do you see wrong with the two getInstance-methods solution? I think this is quite nice and intuitive, making use of code like below:
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:As a user of the API. I should be able to tell if my call to the method was carried out successfully or not. It is not possible to tell this with your approach.

    Like I already indicated that happens a lot in other APIs (Swing, JFace,...) too. I don't see why you need that possibility, because the method should only be invoked once. If you decide to invoke it 10 times you are wasting CPU cycles. But to meet the wishes of my API users I decided to release a new version of my URLyBird application soon with a new method signature for the init-method: returning true when cache is loaded, false otherwise.

    Sean Keane wrote:Ah, ok. So you feel because there is a general usage of a name\signature of a method in the Singleton pattern, and usually this method doesn't take an argument, that by me adding an argument it may be confusing for developers. That is why you think it is a bad idea?

    No, I just don't know what I would pass as the parameter to the getInstance-method when I just need the instance (without the need of initializing the instance based on the parameter). And it could be confusing for a junior programmer who is used to have a no-arg getInstance-method.

    Sean Keane wrote:Yep, and what do you see wrong with the two getInstance-methods solution? I think this is quite nice and intuitive, making use of code like below

    True, but I don't want to repeat these 6 lines every time I want to retrieve a reference to my single instance.
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Just because other API's return uninitialised objects that doesn't mean it is right, or more to the point that it is right in the context of this assignment where we are providing access to a database.

    Changing your init-method to return a boolean indicating success\failure - great idea . That would then remove the issue of not knowing whether the method did anything or not.

    I think it's a fair point that adding a parameter to the getInstance-method could be confusing. So with this in mind it would probably be a good idea to use a different name; maybe getDatabase?

    I was doing some searching to try and find any information on people who faced this problem before - the need to pass information in to the getInstance-method when using the Singleton pattern. I read one reference that said the mere fact that I am trying to do this might suggest that I shouldn't be using the Singleton pattern in the first place.

    I'd love to spend some more time looking into this and alternative solutions\patterns. Definitely one for my to-do list!

    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:Just because other API's return uninitialised objects that doesn't mean it is right

    That was not about the uninitialised objects being returned, but about method calls which you don't know if it did something or not.

    Sean Keane wrote:I read one reference that said the mere fact that I am trying to do this might suggest that I shouldn't be using the Singleton pattern in the first place.

    Could that reference be this thread?
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Nope, the page I was looking at was this guy here. Although the link you posted is interesting too.

    There seems to be a lot of negative feeling around using the Singleton pattern. I wonder what a better solution would be to handle access to the database in our assignment hmmm...
    Jonathan Elkharrat
    Ranch Hand

    Joined: Dec 31, 2008
    Posts: 170

    the singleton pattern is used by lot of exam takers since it assure there's only one thread accessing at a time.
    i always asked myself if using a static variable in the server would serve the same purpose...


    SCJP 5, SCWCD 5, SCBCD 5
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Jonathan Elkharrat wrote:the singleton pattern is used by lot of exam takers since it assure there's only one thread accessing at a time.


    I used to think the same at one stage - that a Singleton would guarantee only one thread was accessing the shared resource at a time. I'm not sure that is entirely true though. It all depends on the context in which your API is used. See this article here.

    In general, I think a lot of the discussions on here we are battling with (1) what is the best & most correct thing to do in general and (2) what is sufficient to do in the context of this assignment. Also, another thing we are probably battling with is implementing our solution versus designing an API. Implementing a solution that works for me, the person who wrote the code, is a lot more straight forward than creating an API where I need to think about other people using that API.

    For (2) I don't mean that I am thinking about doing what is sufficient just to pass. I am thinking about whether I need to consider a certain scenario, whether I need to handle or cater for it. For example, that link I posted above outlines situations where a Singleton turns on not to be a Singleton - but do I need to worry about them for this assignment? Probably not!

    Preserving the class invariant to me is important. I feel like I am shoehorning the Singleton in to my design. I'm sure there is a nicer design.
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Jonathan Elkharrat wrote:the singleton pattern is used by lot of exam takers since it assure there's only one thread accessing at a time.

    if you synchronize its methods otherwise multiple threads can access the object concurrently
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:Preserving the class invariant to me is important. I feel like I am shoehorning the Singleton in to my design. I'm sure there is a nicer design.

    I already noticed it's important to you. I finished reading the Head First Design Patterns book on my holiday and unfortunately for you: the singleton design pattern is in the book, but nothing more (no other design pattern can help you to get around this issue)
    Jonathan Elkharrat
    Ranch Hand

    Joined: Dec 31, 2008
    Posts: 170

    Roel De Nijs wrote:
    Jonathan Elkharrat wrote:the singleton pattern is used by lot of exam takers since it assure there's only one thread accessing at a time.

    if you synchronize its methods otherwise multiple threads can access the object concurrently


    of course.
    what i meant was that if you aren't using a singleton two thread can access the data class, even if it's
    synchronized since another instance can exist in the JVM...
    Dennis Grimbergen
    Ranch Hand

    Joined: Nov 04, 2009
    Posts: 138

    Ok, I'm gonna complain a little about the getInstance() method, probably mentioned before.
    I also faced that fact that it would be handy to have a getInstance(String dbPath) method, because that way I could get the single Data instance and settings the database file location in one call.
    However, I think a method like getInstance() should not have any parameters. A getInstance() is a general accepted form to get a single instance of a class.

    Another reason to use a form like this:

    instead of:

    is that I define that 'readRecords' method in my extended sun provided interface. I do that together with a writeRecords method. Both methods could easily be reimplemented if the database type changes. By providing the filePath to the getInstance method, you would end up without a separate read method. However, one can argue if that is a problem or not. Just my opinion


    SCJP, SCWCD, SCJD
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Roel De Nijs wrote:
    Sean Keane wrote:Preserving the class invariant to me is important. I feel like I am shoehorning the Singleton in to my design. I'm sure there is a nicer design.

    I already noticed it's important to you.


    It's not that preserving the class invariant is important to me. To me it is important. Big difference

    Program correctness is more important than design - I think it would be hard to argue otherwise. For any system you implement you are always going to have to make decisions about design, trade-off's considered, and compromises will have to be made.

    Dennis Grimbergen wrote:However, I think a method like getInstance() should not have any parameters. A getInstance() is a general accepted form to get a single instance of a class.


    Yep, agree here. Roel and I were discussing this on a separate thread. Instead of using getInstance(), another name like getDatabase() could be used.

    Dennis Grimbergen wrote:I define that 'readRecords' method in my extended sun provided interface. I do that together with a writeRecords method. Both methods could easily be reimplemented if the database type changes. By providing the filePath to the getInstance method, you would end up without a separate read method. However, one can argue if that is a problem or not. Just my opinion


    I don't understand the reasoning here. If you use getInstance() to set up your cache, then yes you won't have an init-method in your extended interface. You will only have a method that will trigger writing the cache contents back to the file. I don't see how this approach makes it harder to move the underlying storage to a database going forward.

    If we had a database as the underlying storage, would we even be thinking about using this same design of extending the interface and having init and exit methods? Possibly not?

    When thinking about possible future requirements that don't currently exist, I think it's worth asking the following type questions:

  • Do I really need my design to cater for the possibility of situation X happening sometime in the future?
  • How much impact will not catering for it now and simply refactoring in the future cause? - i.e. will it break users of my API? are there any users of my API other than me?
  • What is the actual probability of me needing to cater for this in the future? You see a lot of people suggesting that you should put a wrapper around your logging mechanism if you are using log4j. Good idea in theory - isolate what may change and insulate it. But in practice, if you start using log4j you are probably not going to change from using it.
  • Is it really possible for me to cater for a possible future feature that I currently have no requirements for and get it 100% right?. You may think you know how something will have to work in the future - but when it comes to the future, it may turn out you were wrong, and the code will need to be refactored anyhow. So you are just adding noise to your code in your first design for no benefit.

  • So when it comes designing our solution to cater for the possibility of a database being used in the future, is there really a strong argument for including this in your design right now?
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Roel De Nijs wrote:
    Sean Keane wrote:Preserving the class invariant to me is important. I feel like I am shoehorning the Singleton in to my design. I'm sure there is a nicer design.
    the singleton design pattern is in the book, but nothing more (no other design pattern can help you to get around this issue)


    Here's an idea. I could add an init() method to my Data class that sets up the cache. Then my getInstance() method wouldn't require any parameter. The catch is that you obviously need to call init() once before you call getInstance() - if you don't, then getInstance() would be set up to return null.

    Positives of this approach are:

  • I don't modify the getInstance() method to add a parameter - so no need to rename it to something else to avoid confusion.
  • Any instance return by the getInstance() method uphold the class invariant.
  • Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:Here's an idea. I could add an init() method to my Data class that sets up the cache. Then my getInstance() method wouldn't require any parameter. The catch is that you obviously need to call init() once before you call getInstance() - if you don't, then getInstance() would be set up to return null.

    And are you really convinced this is a better idea than the 2 getInstance-methods?
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Roel De Nijs wrote:
    Sean Keane wrote:Here's an idea. I could add an init() method to my Data class that sets up the cache. Then my getInstance() method wouldn't require any parameter. The catch is that you obviously need to call init() once before you call getInstance() - if you don't, then getInstance() would be set up to return null.

    And are you really convinced this is a better idea than the 2 getInstance-methods?


    Not convinced. Just an idea I had. But overall yes, I think it is a better solution than two getInstance methods.

  • As we already discussed, a getInstance-method with a parameter is confusing - this solution doesn't require a parameter in the getInstance method. One Plus!
  • The class invariant of the Data class with a cache is that the cache must be loaded, the two getInstance method solution doesn't maintain this invariant - this solution does. Two Pluses!
  • Returning null from the getInstance-method if the Data class is not initialised (by calling the init-method) is intuitive. Three Pluses.


  • Are you convinced that the two getInstance-method solution is better? Or that the one getInstance-method solution where you return an object that doesn't uphold the class invariant is better? Do you see any pluses for either of these two solutions over the one I've proposed. I don't, but would like to hear any viewpoints.
    Dennis Grimbergen
    Ranch Hand

    Joined: Nov 04, 2009
    Posts: 138

    Sean Keane wrote:Returning null from the getInstance-method if the Data class is not initialised (by calling the init-method) is intuitive.

    I don't know. I, as an API user, would never expect to receive a null because I expect the single non-null instance of that particular class.

    Why not use 2 statements?
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Dennis Grimbergen wrote:
    Sean Keane wrote:Returning null from the getInstance-method if the Data class is not initialised (by calling the init-method) is intuitive.

    I don't know. I, as an API user, would never expect to receive a null because I expect the single non-null instance of that particular class.


    The Singleton pattern as is commonly implemented does not 100% fit the use case here. So any solution is not going to be what you would normally expect. Plenty of API's return null in certain situations.

    Dennis Grimbergen wrote:Why not use 2 statements?


    The two statements here is simply using the init-method we discussed earlier in the thread. The negative point associated with this solution is discussed here and it's the solution I mentioned in my previous post
    Sean Keane wrote:Or that the one getInstance-method solution where you return an object that doesn't uphold the class invariant
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    I guess the (static) init-method will just set the databaseLocation which is afterwards used in the getInstance-method (or the constructor) to load the records into your cache.

    Sean Keane wrote:As we already discussed, a getInstance-method with a parameter is confusing - this solution doesn't require a parameter in the getInstance method. One Plus!

    It's true you know have just 1 getInstance-method, but you have to know you have to call the init-method. So that's also confusing because you wouldn't expect that with a singleton design pattern.

    Sean Keane wrote:The class invariant of the Data class with a cache is that the cache must be loaded, the two getInstance method solution doesn't maintain this invariant - this solution does. Two Pluses!

    I don't know why suddenly the 2 getInstance-method solution does not maintain the class invariant, because you opted for that solution (above the solution with the getInstance + instance init-method I used) just because it maintained the class invariant.

    Sean Keane wrote:Returning null from the getInstance-method if the Data class is not initialised (by calling the init-method) is intuitive. Three Pluses.

    Like Dennis I certainly not find this intuitive, because you would not expect that at all. A singleton's getInstance method returning null It should return the one and only instance.
    Secondly, I think it's better to throw an IllegalStateException (instead of returning null), because it's wrong usage of the API. If I use your API (and I don't have the source code) and I call getInstance I receive null and I will because I don't know why. Using an IllegalStateException you can add a description to instruct your API-user what is expected (that's what I did too when he calls a method before calling the init-method).

    Sean Keane wrote:Are you convinced that the two getInstance-method solution is better? Or that the one getInstance-method solution where you return an object that doesn't uphold the class invariant is better? Do you see any pluses for either of these two solutions over the one I've proposed. I don't, but would like to hear any viewpoints.

    First of all to avoid another (very) long discussion based on subjective arguments, making design decisions is about considering trade-offs and you (always) have to make some comprises (and I'm a Belgian, so should be good at it, because that's what we here do all the time ).
    I chose for a text-book singleton with an interface containing an init and exit method. The biggest plus about this approach is that you have all your methods defined in an interface, so when you want to change your current implementation with another one or create a new class to handle e.g. hotel info it can be done by simply implementing all methods from the interface. It also can be done by a different team than the team reponsible for business layer and/or client. The more static methods you have, the harder it will be because more code depend on an implementation (which violates the design principle "code to an interface, not an implementation"). For me this approach is also as intuitive as the other approaches (but that's a subjective argument, so just leave it this way).
    You can argue that you should not take into account possible extensions which even might never happen, but I don't agree with it. When an application is great, more functionality will almost certainly be added and so you better be ready for it. That's another design principle: a design should be closed for modification, but open for extension. And I'm willing to sacrifice the class variant in this situation for a clean, easy-to-extend design (also because with the intended API usage there'll be no problem and the API is also protected to prevent illegal API usage), because these design principles are more important to me than the class variant.
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    I think I mentioned too myself earlier that design invovlves trade-offs and compromises . That is what I am discussing here. Different solutions, pro's & con's. There is no 100% correct solution.

    I think too it is worth leaving aside design patterns for a moment and actually looking at the solution. Because it's possible we are getting hung on a solution not being how the Singleton pattern is normally implemented, and being worried that people will be confused that it doesn't match the Singleton pattern.

    The second solution I proposed involves two things:

  • Initialising a class so that the cache is loaded and it is in a valid state.
  • Providing a method that returns an initialised instance of this class that upholds the class invariant.


  • This is quite intuitive. You want to use my class - then you initialise it and then get an instance of it. It is no more unintuitve as the solution you went for. You want to use your class - then you get an instance and then initialise it.

    The only difference between the two solutions is in when you initialise the class. To me it is more intuitive to initialise it first - but that may not be the case for you.

    So I don't see approach you went for having any added benefit over the approach I am proposing - it is no more intuitive. Whereas the approach I am proposing has an added benefit over the approach you went with - in that it always returns an instance that maintains the class invariant. And in coding terms, it means I don't need to include a check in every single method that operates on the cache.

    As a general principle, program correctness I would argue is more important than design. Because the program being correct is what it's all about at the end of the day.

    But leaving aside whether aside program correctness and just concentrating on design. I couldn't understand from your explanation how in reality the solution you went for is a better design. I don't see how that solution allows me to more easily change to another implementation. The whole reason you are using a Singleton is because you only want one instance - is it going to be any different if you change your implementation to use a real database?
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:I couldn't understand from your explanation how in reality the solution you went for is a better design. I don't see how that solution allows me to more easily change to another implementation.

    Because everything you'll need to create another dao (for another database file) is in the interface (except for the getInstance-method if you want another singleton). The more static-methods you have in your Data class, the more dependencies you have in your code and the harder it will be to change to another implementation (or to create a similar dao for another database file).
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Roel De Nijs wrote:
    Sean Keane wrote:I couldn't understand from your explanation how in reality the solution you went for is a better design. I don't see how that solution allows me to more easily change to another implementation.

    Because everything you'll need to create another dao (for another database file) is in the interface (except for the getInstance-method if you want another singleton). The more static-methods you have in your Data class, the more dependencies you have in your code and the harder it will be to change to another implementation (or to create a similar dao for another database file).


    Yes, I understand the theory. Theory is always good . But in reality, what are the concrete benefits with your solution if you had to switch over from a file to say a relational database? Taking into consideration that you are using a Singleton because you only ever want one instance of the object regardless of what the underlying implementation is.
    Roel De Nijs
    Bartender

    Joined: Jul 19, 2004
    Posts: 4910
        
      10

    Sean Keane wrote:But in reality, what are the concrete benefits with your solution if you had to switch over from a file to say a relational database? Taking into consideration that you are using a Singleton because you only ever want one instance of the object regardless of what the underlying implementation is.

    I can't keep repeating myself. What I described in a previous posts are the (concrete) benefits of my solution. All your DAOs will work through an identical interface, but implementations could be different and if you combine that together with a DAO factory, then you can easily switch between implementations.
    Sean Keane
    Ranch Hand

    Joined: Nov 03, 2010
    Posts: 581

    Roel De Nijs wrote:
    Sean Keane wrote:But in reality, what are the concrete benefits with your solution if you had to switch over from a file to say a relational database? Taking into consideration that you are using a Singleton because you only ever want one instance of the object regardless of what the underlying implementation is.

    I can't keep repeating myself. What I described in a previous posts are the (concrete) benefits of my solution. All your DAOs will work through an identical interface, but implementations could be different and if you combine that together with a DAO factory, then you can easily switch between implementations.


    Yep I understand the general principle and benefit of coding to interfaces. But in practice all it means that in your DAOFactory you will have something like:

    Whereas in the solution where the Singleton class is initialised before getting an instance you would have:

    The only difference between the two solutions if you want to change the underling implementation of the DB interface is in your solution you implement the init-method as an instance method, whereas the second solution you will implement it as a static class method.

    In both solutions you will have to implement the init-method() and in both solutions you implement it in the same class. So I don't see any concrete benefit here in design terms of one approach over the other. Am I missing something?
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Cache in Data Class
     
    Similar Threads
    get all records in GUI in B&S
    Extending Sun's/Oracle's interface - IOException
    statin vs. nonstatic methods
    Making the Data Class a Singleton & Thread Safe
    Is accessing static class variables from non-static methods bad practice?