2012-08-26 15 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.

Powiązane problemy