1

I have the following problem - I write the code for object data manager, and one of requirements is being able to save/load data into some persistent data storage. I want to make it as the following:

  • there is an interface, IPersistentDataService.
  • if user uses an option to save/load from file, they can give arbitrary filename and save/load data.
  • if user uses an option to save to database/load from database, they set database connection parameters once (server, database, username, password, trusted connection etc), and then proceed to save/load from database
  • if user uses an option to save/load using API, they give api address and credentials.

I have the trouble setting one consistent interface for all the cases. Of course I can make something like:

public interface IPersistentStorage{
    void Save(IDatabase database);
    IDatabase Load();
}

but then I cannot use arbitrary filename given by user when saving/loading from file - it has to be set when building IPersistentStorage object.

3 Answers 3

1

I have the trouble setting one consistent interface for all the cases.

That's because there is no consistent interface. In the "save to file" case, you need to pass in a parameter every time the Save method is called, while in the database and API cases there is no parameter to Save - those are different interfaces.

1
  • Note that this answer is correct based on OP's current idea; but there is the alternate option of setting the filename on a per-instance level, e.g. because the repo uses one file for its entire storage or one file format which can then be dynamically generated (e.g. adding in the entity ID) without needing a per-method-call parameter to be passed. If OP's intent of reusing the interface is more pertinent than being able to pass a completely arbitrary filename on a per-method-call basis, this answer somewhat misses the mark. Based on the accepted answer, this seems to be the case.
    – Flater
    Commented Jun 1, 2023 at 0:58
1

I found an answer - I should just create Reader/Writer interface and pass it as follows:


IPersistentStorage ps1 = new FileStorage("file.txt");
IPersistentStorage ps2 = new DatabaseStorage("localhost", "database", etc...);
IPersistentStorage ps3 = new ApiStorage("https://api...", "username", "password");

objectService.save(ps1);
objectService.save(ps2);
objectService.save(ps3);

objectService.load(ps1);
objectService.load(ps2);
objectService.load(ps3);
0
0

You can start creating a StorageService class that can be called instead

storageservice_file = StorageService('file')
storageservice_file.save(some_obj)
storageservice_file.load(some_obj)

storageservice_db = StorageService('file')
storageservice_db.save(some_obj)
storageservice_db.load(some_obj)

StorageService's constructor can initialize FileStorage class or DatabaseStorage class. Each specific Storage should have its own implementation of save or load.

Furthermore, complying with SOLID principles, you can implement Factory to initiate FileStorage or DatabaseStorage and use that Factory class/method inside StorageService instead of the direct reference of FileStorage or DatabaseStorage.

One suggestion, use patterns that address the complexities and are not required to change often.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.