Oggi ho ricevuto una lettera di rifiuto da una società in cui durante il processo di intervista hanno dato un paio di giorni per rispondere alla seguente domanda (parafrasata):
Let’s say say you have instances of class UserReview and need to save them somehow, using a storage service of some sort.
Please provide pseudocode, draft code or a clear description that indicates how you would save these UserReview objects to a storage service in such a way as to allow:
The storage service to be changed at some unknown point in the future, for example, from an in-house service to a cloud service, minimizing impact on the Android code particularly avoiding changes directly to the UserReview class itself. (Don’t worry about the API interface to the remote store unless that is key to your solution.)
The design pattern(s) adopted and implemented for UserReview to be leveraged, minimizing code duplication, to allow other objects (e.g. a new class called SellerResponse) to be saved in a similar way.
Key to our interest in this problem is how you would accomplish these two goals efficiently and cleanly, maximizing Object Oriented reusability and flexibility while avoiding overdesigned code and the Android design patterns and language features that you would use to do so.
Ho risposto alla domanda con il codice utilizzando il seguente interface
:
//To add a new Remote Store, just implement a Saver class for it
//and it will work with all the other classes that use Saver.
public interface Saver {
//Ultimately, every Object should be representable as a series of bytes,
//and every data store should be able to store bytes. In the worst case
//we can use base64 to encode Objects as strings.
SaverResult save(InputStream data);
}
//This is one way of allowing code that uses Savers to respond to errors/unavailability.
//Of course, we could also subclass Exception and then throw it, but this way allows us to
//easily chain multiple save requests without multiple nested try-catch blocks.
static class SaverResult {
public final boolean failed;
public final String errorMessage;
SaverResult(boolean failed) {
this(failed, null);
}
SaverResult(boolean failed, String errorMessage) {
this.failed = failed;
this.errorMessage = errorMessage == null ? "" : errorMessage;
}
}
Ho anche incluso alcuni esempi di utilizzo di Saver interface
includendo un esempio di Dependency Injection
, (ovvero una classe con un costruttore come questo: public UserReview(String review, String username, long id, Saver saver)
) e un esempio di mantenere l'istanza Saver
all'esterno del oggetto da salvare e mostrare come ciò consente di salvare facilmente l'oggetto su due diversi servizi.
Ad esempio:
s3.save(Common.toInputStream(review1.toString()));
inHouse.save(Common.toInputStream(review1.toString()));
Era un buon modo per rispondere alla domanda? Esiste un modo migliore? C'era qualcosa di importante che mi mancava?
Chiedo non solo di poter fare meglio nelle interviste future, ma anche perché voglio sapere se c'è una ragione per cui questa non sarebbe una buona soluzione se il problema si presentasse effettivamente.