Questa interfaccia di metodo è una buona risposta a questa domanda di intervista?

1

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 pseudo­code, 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:

  1. 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.)

  2. 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 over­designed 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.

    
posta Ryan1729 23.02.2017 - 01:50
fonte

2 risposte

2

Ciò che ti stanno essenzialmente chiedendo è di implementare e descrivere un schema del repository .

Penso che la cosa che ha sparato all'intera soluzione sia questa:

Ultimately, every Object should be representable as a series of bytes, and every data store should be able to store bytes.

Questo è totalmente, completamente, completamente sbagliato. Se, ad esempio, stavi memorizzando oggetti in un database relazionale, vorresti che ciascun campo di quell'oggetto fosse una singola colonna. Salvare solo la stringa Base64 per ogni oggetto limiterebbe drasticamente l'indicizzazione e l'interrogazione. Un altro problema con questo è in quale formato sarebbero i dati binari? Se il codice utilizza una sorta di serializzazione binaria proprietaria, sarebbe complicato interrogare i dati da una posizione diversa.

UserReview(String review, String username, long id, Saver saver)

Tutti gli oggetti dominio non dovrebbero avere idea di come vengono salvati. Questo è vicino (ma non esattamente) uno schema di registrazione attivo. È da alcuni, considerato un anti-pattern, e quindi un cattivo design.

    
risposta data 23.02.2017 - 06:29
fonte
0

Ci sono diversi modi per progettare questo sistema, e nessuno sa cosa cercasse specificamente l'azienda. Quello che posso fare, tuttavia, è mostrarti il mio processo di pensiero e come lo progetterei.

Prima di tutto, il tema qui è disaccoppiamento di oggetti e servizi di dati. Dovremmo essere in grado di serializzare un oggetto attraverso qualsiasi servizio, e ogni servizio dovrebbe essere in grado di serializzare qualsiasi oggetto dati.

Ci sono due modi principali per raggiungere questi obiettivi in Java.

Prima di tutto, devo sottolineare che la dichiarazione del problema non menziona alcun vincolo sugli oggetti dati - sono POJO Java bean? Sono più complessi? Non ne ho idea.

Interfacce

Potremmo taggare ogni oggetto dati con un'interfaccia che lo contraddistingue come accettabile da salvare su un servizio. Java include già una di queste interfacce, java.io.Serializable . Potremmo riutilizzarlo.

Allo stesso modo, i servizi hanno un'interfaccia che specifica che possono serializzare oggetti: forse un metodo public void serialize(Serializable obj) . Nota che non si fa menzione di deserializzazione o caricamento di oggetti.

Questo è l'approccio più tradizionale, "vecchia scuola".

NOTE

Il modo in cui implementerei questo è tramite annotazioni di bean Java, preferibilmente attraverso un framework come Primavera .

Questo ha alcuni seri vantaggi:

  • Nessuna dipendenza dall'interfaccia. La "interfaccia" è documentata tramite annotazioni (o file di configurazione come XML o proprietà), ponendo pochi vincoli sul codice esistente.

  • Invece di chiedersi come si localizzerà una particolare definizione o servizio di bean (oggetto di dati), chiedete a Spring di individuarlo per voi. Ciò significa che scrivi molto meno codice per "incollare" il tuo codice alle definizioni esterne di oggetti o servizi di dati. Si rinuncia alla sicurezza del tipo statico in fase di compilazione per eccessiva configurazione e delega in fase di runtime, che in realtà finisce per essere migliore: ora è possibile rilasciare i file jar con i servizi e non pensare mai a come capire cosa sono. Il processore di annotazione di Spring li trova per te.

  • Facilità d'uso. Chiama Spring per ottenere un oggetto particolare e in una riga di codice puoi ottenerlo. Non è necessario scavare nelle fabbriche o in altri modelli (che si basano su altri modelli e finiscono per darti una classe come BeanSerializationServiceLocatorAbstractFactory che è letteralmente il bersaglio delle battute su Java).

Non sono un esperto di Android, ma credo che abbia strutture simili integrate.

Non ho intenzione di darti alcun codice: spero che descrivendo il mio processo ti aiuterò di più. Forse dovresti creare un progetto di prova per sapere come farlo funzionare e chiedere a SoftwareEngineering.SE una recensione del progetto .

    
risposta data 23.02.2017 - 03:06
fonte

Leggi altre domande sui tag