2012-08-26 12 views
5

To pytanie jest nieco ogólne i koncepcyjne.Zapobieganie wywoływaniu metody przed innym

Mam zajęcia z różnymi metodami. Nazwijmy je A i B. Jak mogę się upewnić, że inni programiści pracujący z tą klasą w przyszłości nie wywołają metody B przed pierwszym wywołaniem metody A co najmniej raz?

Robię to w C++, ale ogólnie, jaki jest najlepszy sposób na wymuszenie tego? Mam naiwne pomysły, takie jak użycie zmiennej binarnej, ale chciałbym również usłyszeć inne myśli.

+0

nie można naprawdę egzekwować zamówienia (masz już wymienione rozwiązanie). Możesz ponownie zaprojektować wzór szablonu i uniknąć tej szczególnej potrzeby. http://pl.wikipedia.org/wiki/Template_method_pattern – Jayan

Odpowiedz

10

Jeden sposób na zagwarantowanie tego? Obowiązkiem metody B jest jednorazowe wywołanie metody A.

Wszystko inne to delikatne API.

+1

To jest dobry pomysł (+1), Należy pamiętać, że wadą tego jest to, że wszystkie informacje potrzebne do wykonania połączenia A muszą być przekazane do B - ta może być smutny. (Wyobraź sobie, że musisz przekazać wszystkie dane połączenia DB do każdego zapytania ...) –

+0

Również "Tylko droga" to trochę mocne IMO. –

+0

OK, zalety. –

4

Mieć zmienną boolean, która określa, czy został wywołany A. Następnie, gdy ktoś próbuje wywołać B bez ustawionej zmiennej boolowskiej, wyrzuć wyjątek IllegalStateException.

Albo możesz mieć B po prostu zadzwoń pod A, ponieważ wydaje się, że nie można go wykonać bez uprzedniego wywołania A.

W przeciwnym razie, a ponieważ obie metody są publiczne, nie ma innego sposobu na wymuszenie tego.

5

Użycie funkcji boolowskiej to dobry start, a dostęp do rzucania działa poprawnie.

Czasami jednak jest miło móc to wymusić podczas kompilacji. W takim przypadku jedyną realną opcją jest użycie niektórych lew.

wystawiać tylko w swojej klasie, sprawiają, że powrót pełnomocnika zawierającego 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. 
} 

można również osiągnąć coś podobnego za pomocą chronionego dziedziczenie z klasy bazowej wykonawczych (lub dostarczenie wirtualny) B().

5

Jednym ze sposobów jest przeprojektowanie klasy nieco inaczej. Rozważ prostą klasę bazy danych, która musi zostać zainicjowana przed użyciem. Jestem facetem Javy, więc ...

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

Muszę najpierw wywołać init. Mogę utworzyć DatabaseFactory, który inicjuje i zwraca rzeczywisty obiekt bazy danych. Możemy ukryć konstruktor, aby tylko DatabaseFactory mógł utworzyć bazę danych (w Javie jest klasą zagnieżdżoną, w C++ może być klasa przyjaciół?).

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

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

Teraz muszę przejść przez fabrykę, aby dostać się do ukrytego obiektu.

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

Jednym ze sposobów zagwarantowania tego jest wykonanie A w konstruktorze klasy. Jeśli konstruktor nie powiedzie się (wyrzuci), pozostali programiści nie mają nic wspólnego z tym, co zrobić z tym błędnym B. Jeśli konstruktor się powiedzie, to A zostanie wykonane co najmniej raz, a więc B jest prawidłową operacją do wykonania.

2

Chciałbym uczynić metodę "A" konstruktorem, aby zainicjować obiekt. To musi być wywołane raz, aby użyć obiektu, wymuszonego przez kompilator.Później możesz wywołać metodę "B" ze świadomością, że konstruktor musiał zostać wywołany.