Być może to bardziej nadaje się do działu inżyniera oprogramowania, jako że na etapie projektowania takie rzeczy powinno się rozwiązać, ale że jest już troche kodu i jakaś implementacja to wrzuciłem to tutaj.
Chciałbym spytać się o rozwiązanie następującego problemu.
Piszę sobie obsługę takiego systemu gdzie mam jakieś urządzenia i komendy/polecania które mogą przychodzić z zewnątrz i danym urządzeniem sterować.
Mam zaimplementowany observer (jako szablon) który słucha komend przychodzących z sieci i wywołuje odpowiednia metodę (update()) w której mogę wykonać sobie odpowiednie instrukcje.
Klasa obserwer wyglada tak (pomijam implementację metod attach, notify i update, to działa poprawnie):
template <typename Msg>
class Observer {
public:
virtual ~Observer () {}
virtual void update (Msg message) = 0;
};
Specyfikacja szablonu dla jakiegoś konkretnego typu wiadomości wygląda np. tak:
template<>
class Observer<Mode> {
void update(Mode msgMode){
...
}
}
Do obsługi przychodzących wiadomości po sieci mam też klasę ReceiverX1 (XX - identyfikator urządzenia), która używa obserwer aby dostawać tylko konkretny typ wiadomości (dodatkowo klasa ReceiverXX implementuje metody, które sprawdzają poprawność danych przychodzących). Tych receiverów jest kilka, w zależności od tego jakiego urządzenia jest to odbiornik, każdy z tych Receiverów dziedziczy po klasie abstrakcyjnej Receiver i implementuje swoją metodę receive().
//klasa abstrakcyjna & interfejs
class Receiver {
public:
virtual void receive() = 0;
};
No i teraz taki przykładowy Receiver odbierający jakąś wiadomość (lub więcej wiadomości). Klasy CommunicationChannel nie będę wklejał, zajmuje się ona obsługa danych na poziomie soketów.
class ReceiverX1 {
public:
void receive(){
Observer<Mode> observerMode {};
cc.attach(observerMode); //cc - obiekt klasy CommunicationChannel
while(true){
cc.recv();
}
}
};
Mam też klasę która określa mi jakieś urządzenie (np. DeviceX1) i wykonuje na nim odpowiednie operacje, np., zaczyna nasłuchiwać przychodzących wiadomości, wykonuje jakieś akcje po otrzymaniu danej komendy.
class DeviceX1 {
public:
void start(){
thread recX1(&ReceiverX1::receive, receiverX1);
recX1.detach();
while(true){
...
}
}
void changeMode(DeviceMode devMode){
switch(devMode){
case DeviceMode::ON:
...
break;
case DeviceMode::OFF:
...
break;
}
};
...
private:
DeviceMode mode;
unique_ptr<Receiver> receiverX1;
}
No i teraz co ja chciałbym osiągnąć?
Chciałbym w metodzie update() w klasie Observer<...> mieć dostęp do instancji obiektu danego urządzenia, by np. w momencie otrzymania jakiejś wiadomości móc zareagować i wywołać metodę obsługującą dane zdarzenie. Jednocześnie chciałbym móc w klasie DeviceX1 uruchomic metodę receive() obiektu ReceiverX1. Jak to zrobić? Jest tutaj zależność klas DeviceX1 i ReceiverX1, których obiekty wzajemnie się wykorzystują.
ReceiverX1 potrzebuje referencję do obiektu DeviceX1 aby móc przekazać ją do konstruktora obiektu Observera danej wiadomości.
DeviceX1 potrzebuje obiektu ReceiverX1 aby dostać się do metody receive() i uruchomić odbieranie wiadomości gdy urządzenie będzie gotowe.