Reputation: 331
I have a class of a Student. When I call a method that gets a client, it returns a newly created Student object. The constructor of Student gets the required data from the database by calling the method getStudentData. However, getStudentData takes an incredibly long time due to the nature of the database.
I initially implemented a factory design pattern, but it did not work as I had hoped. Note that I have to use getStudentData, and I am unable to change the database.
The Student class is as below:
public class StudentImplementation implements Student {
private final int key;
private String givenName;
private String surname;
private String contactNumber;
private String email;
private String address;
public StudentImplementation(Login account_tokenizer, int key) {
this.key = key;
this.givenName = Table.getInstance().getStudentData(account_tokenizer, key, "givenName");
this.surname = Table.getInstance().getStudentData(account_tokenizer, key, "surname");
this.contactNumber = Table.getInstance().getStudentData(account_tokenizer, key, "contactNumber");
this.email = Table.getInstance().getStudentData(account_tokenizer, key, "email");
this.address = Table.getInstance().getStudentData(account_tokenizer, key, "address");
}
// The rest of the class is full of getters
}
Upvotes: 0
Views: 450
Reputation: 3592
If you can't fetch all the data in a single request maybe you could try to parallelize it if the db connection supports it.
public StudentImplementation(Login account_tokenizer, int key) {
this.key = key;
Table table = Table.getInstance();
CompletableFuture.allOf(
CompletableFuture.runAsync(() -> this.givenName = table.getStudentData(account_tokenizer, key, "givenName")),
CompletableFuture.runAsync(() -> this.surname = table.getStudentData(account_tokenizer, key, "surname")),
CompletableFuture.runAsync(() -> this.contactNumber = table.getStudentData(account_tokenizer, key, "contactNumber")),
CompletableFuture.runAsync(() -> this.email = table.getStudentData(account_tokenizer, key, "email")),
CompletableFuture.runAsync(() -> this.address = table.getStudentData(account_tokenizer, key, "address"))
).join();
}
Upvotes: 0
Reputation: 4034
First of all, you can keep the result of the call to Table.getInstance()
in a local variable – although, without knowing what this method is really doing, it may spare you only milliseconds …
public StudentImplementation(Login account_tokenizer, int key) {
this.key = key;
var instance = Table.getInstance();
this.givenName = instance.getStudentData(account_tokenizer, key, "givenName");
this.surname = instance.getStudentData(account_tokenizer, key, "surname");
this.contactNumber = instance.getStudentData(account_tokenizer, key, "contactNumber");
this.email = instance.getStudentData(account_tokenizer, key, "email");
this.address = instance.getStudentData(account_tokenizer, key, "address");
}
And usually, you would not login into the database for each attribute separately. But as that is your API, you have to live with it … bad performance is, in this case, not your fault.
Nevertheless, having the database access in the Constructor of StudentImplementation
is a bad idea: how do you create a new Student that is not yet in the database?
And database access tend to fail, so your Constructor may fail as well, and there is a rule of thumb (no law!) that Constructors should not throw exceptions from their internal operations (something that cannot be avoided all the time, but you should try …).
So having a Constructor that takes the attributes and a factory method that collects the data from the database and then calls the Constructor would be the better design – although it will not solve your performance issue.
Upvotes: 2