2012-08-26 18 views
5

Questa è una domanda un po 'ampia e concettuale.Prevenire un metodo chiamato prima di un altro

Ho una classe con vari metodi. Chiamiamoli A e B. Come posso assicurarmi che altri sviluppatori che lavorano con questa classe in futuro non chiameranno il metodo B prima di chiamare il metodo A almeno una volta?

Sto facendo questo in C++ ma in generale qual è il modo migliore per far rispettare questo? Ho idee ingenue come l'uso di una variabile booleana, ma mi piacerebbe sentire anche altri pensieri.

+0

non si può davvero far rispettare l'ordine (hai già una soluzione menzionata). Potresti riprogettare con un modello di modello ed evitare questa necessità speciale. http://en.wikipedia.org/wiki/Template_method_pattern – Jayan

risposta

10

Un modo per garantire questo? Rendi la responsabilità del metodo B di chiamare il metodo A una volta.

Qualsiasi altra cosa è una API fragile.

+1

Questa è una buona idea (+1), si noti che uno svantaggio di questo è che tutte le informazioni necessarie per effettuare la chiamata ad A devono essere passate in B - questo può essere tristi. (Immagina di dover passare tutti i tuoi dati di connessione DB ad ogni query ...) –

+0

Anche "Only way" è un IMO un po 'forte. –

+0

OK, buoni punti. –

4

Avere una variabile booleana che determina se è stato chiamato A. Quindi, quando qualcuno tenta di invocare B senza impostare questa variabile booleana, lanciare un IllegalStateException.

Oppure si potrebbe avere B semplicemente chiamare A poiché sembra che non possa essere eseguito senza A essere chiamato prima comunque.

Altrimenti, e poiché entrambi i metodi sono pubblici, non c'è davvero altro modo per far rispettare questo.

5

L'utilizzo di un booleano è un buon inizio e il lancio dell'accesso funziona correttamente.

Tuttavia a volte è bello poterlo applicare in fase di compilazione. In quel caso la tua unica vera opzione è usare alcuni trucchi.

esporre solo una nella classe, ne fanno restituire un proxy che contiene B.

class MyClass { 
    public: 

    struct BProxy { 
     public: 
     MyClass * root; 
     void B() { root->B(); } 
     protected: 
     BProxy(MyClass * self) : root(self) {}; // Disable construction 
     friend class MyClass; //So that MyClass can construct it 
    }; 

    BProxy A() { ... return BProxy(this); } 
    friend class BProxy; // So that BProxy can call B() 
    protected 
    void B() { ... } 
}; 

int main() { 
    MyClass m; 
    BProxy bp = m.A(); 
    // m.B(); can't do this as it's private - will fail at compile time. 
    bp.B(); // Can do this as we've got the proxy from our previous call to A. 
} 

È inoltre possibile ottenere qualcosa di simile utilizzando l'ereditarietà protetta da un baseclass attuazione (o fornire un virtuale) B().

5

Un modo è ridisegnare la tua classe in modo un po 'diverso. Si consideri una semplice classe di database che deve essere inizializzata prima di essere utilizzata. Sono un ragazzo Java, quindi ...

public class Database { 
    public void init(String username, String password) // must call this first! 
    public List<Object> runQuery(String sql) // ... 
} 

quindi ho bisogno di chiamare init prima. Posso creare una DatabaseFactory che esegue l'inizializzazione e restituisce l'oggetto del database effettivo. Possiamo nascondere il costruttore in modo che solo DatabaseFactory possa creare un database (in Java una classe nidificata, in C++ forse una classe di amici?).

public class DatabaseFactory { 
    public Database init(String username, String password) // ... 

    public class Database { 
    private Database() {} 
    public List<Object> runQuery(String sql) // ... 
    } 
} 

Quindi ora devo passare attraverso la fabbrica per raggiungere l'oggetto sottostante.

2

Un modo per garantire che sia A eseguito nel costruttore della classe. Se il costruttore fallisce (getta), allora gli altri sviluppatori non hanno nulla con che cosa fare con questo errato B. Se il costruttore ha esito positivo, lo A viene eseguito almeno una volta e quindi B è un'operazione valida da eseguire.

2

Vorrei rendere il metodo "A" al costruttore per inizializzare l'oggetto. Questo deve chiamare una volta per usare l'oggetto, applicato dal compilatore.Successivamente è possibile chiamare un metodo "B" nella consapevolezza che deve essere stato chiamato un costruttore.

Problemi correlati