2012-08-26 26 views
5

Esta es una pregunta un tanto amplia y conceptual.Evitar que se llame a un método antes que otro

Tengo una clase con varios métodos. Vamos a llamarlos A y B. ¿Cómo puedo asegurarme de que otros desarrolladores que trabajen con esta clase en el futuro no invoquen el método B antes de llamar primero al método A al menos una vez?

Estoy haciendo esto en C++ pero, en general, ¿cuál es la mejor manera de hacer cumplir esto? He ingeniado algunas ideas, como usar una variable booleana, pero me gustaría escuchar algunas otras ideas también.

+0

realmente no se puede hacer cumplir la orden (ya tiene una solución mencionada). Es posible que pueda volver a diseñar con el patrón de plantilla y evitar esta necesidad especial. http://en.wikipedia.org/wiki/Template_method_pattern – Jayan

Respuesta

10

¿Una forma de garantizar esto? Haga que la responsabilidad del método B sea llamar al método A una vez.

Todo lo demás es una API frágil.

+1

Esta es una buena idea (+1), tenga en cuenta que una desventaja de esto es que toda la información necesaria para realizar la llamada a A debe pasarse a B; esto puede estar triste. (Imagine que necesita pasar todos los datos de su conexión de base de datos a cada consulta ...) –

+0

También "Only way" es un poco fuerte IMO. –

+0

Bien, buenos puntos. –

4

Tiene una variable booleana que determina si se ha llamado A. Luego, cuando alguien intente invocar B sin que se establezca esta variable booleana, ejecute una IllegalStateException.

O podría tener B simplemente llame al A ya que parece que no se puede ejecutar sin que A se llame primero de todos modos.

De lo contrario, y dado que ambos métodos son públicos, realmente no hay otra forma de hacer cumplir esto.

5

El uso de un booleano es un buen comienzo y el acceso funciona correctamente.

Sin embargo, a veces es bueno ser capaz de hacer cumplir esto en tiempo de compilación. En ese caso, tu única opción real es usar algunos trucos.

Sólo exponer una en su clase, hacerlo volver de un proxy que 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. 
} 

También puede lograr algo similar utilizando la herencia protegida de una clase base de aplicación (o proporcionar un virtual) B().

5

Una forma es rediseñar su clase un poco diferente. Considere una clase de base de datos simple que debe inicializarse antes de ser utilizada. Soy Java, así que ...

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

Así que necesito llamar a init primero. Puedo hacer una DatabaseFactory que realice la inicialización y devuelva el objeto de base de datos real. Podemos ocultar el constructor para que solo una DatabaseFactory pueda crear una base de datos (en Java una clase anidada, en C++ ¿una clase de amigo quizás?).

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

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

Así que ahora debo pasar por la fábrica para llegar al objeto subyacente.

DatabaseFactory factory = new DatabaseFactory(); 
Database database = factory.init("username", "password"); // first init (call method A) 
// now I can use database (or B in your case) 
database.runQuery("select * from table"); 
2

Una forma de garantizarlo es que A se realiza en el constructor de la clase. Si el constructor falla (arroja), entonces los otros desarrolladores no tienen nada con qué hacer que erróneamente B con. Si el constructor tiene éxito, entonces A se realiza al menos una vez, por lo que B es una operación válida.

2

Haría que el método "A" el constructor inicializara el objeto. Esto tiene que llamar una vez para usar el objeto, impuesto por el compilador.Más tarde puede llamar a un método "B" sabiendo que se debe haber llamado a un constructor.

Cuestiones relacionadas