Zależności pomiędzy klasami

0

Witam,
Mam dwie klasy TcpClient oraz Communication. TcpClient odpowiada za komunikacje tcp (metody connect, disconnect, write, read), a Communication za dekodowanie otrzymanych pakietów/ramek oraz ich wysyłanie.
Na tym etapie zrodziły się trzy pytania:

  1. Jak przekazać metody klasy TcpClient do klasy Communication? Czy Communication powinna dziedziczyć po TcpClient ? Globalny wskaźnik do metody TcpClient?
  2. Oraz jak mona zrobić to samo bardziej ogólnie np jeśli zamiast klasy TcpClient chciałbym użyć klasy SerialPort, czyli zmienić tylko interfejs jakim będą wysyłane i odbierane pakiety.
  3. Możecie polecić jakieś materiały, przykładowe programy, hasła pod jakimi szukać jak powinno rozwiązywać się podobne problemy.
2
  1. Wydaje mi się, że dziedziczenie odpada, lepsza będzie kompozycja. Czyli klasa Communication zawiera wskaźnik na obiekt TCP i korzysta z jego publicznego interfejsu.
  2. TCP i Serial niech dziedziczą po wspólnej klasie. Wtedy w Communication znajdzie się wskaźnik na klasę bazową.
  3. Szukaj tematów dziedziczenie vs kompozycja, ew. o wzorcach projektowych.
1

Ja bym rozłożył klase Communication. Teraz będzie odpowiedzialna za dekodowanie wiadomości oraz wysyłanie za pomocą klasy TCP.
Podzieliłbym na klasę ktora. Dekoduje wiadomości oraz druga która zarządza ruchem.

Nie używaj dziedziczenia, bo mimo że concept rozumiesz to chcesz używać jako złoty środek na wszystko. Korzystaj z kompozycji

Póki co zrób sobie zasadę że będziesz dziedziczyć jedynie po interfejsach / klasach abstrakcyjnych, które definiują zachowanie klasy. W ten sposób będziesz mógł mieć w menedżerze kilka protokołów mimo że menedżer będzie posiadał tylko Smart pointer do interfejsu

2

Po pierwsze zdefiniuj interface (do modyfikacji, bardziej przykład):

class IClient
{
public:
    virtual ~IClient() = default;

    virtual int connect(const std::string& addr, int port) = 0;
    virtual int disconnect() = 0;
    virtual int write(const std::vector<char>& data) = 0;
    virtual int read(std::vector<char>& data) = 0;
};

Po drugie niech Communication przyjmuje jako parametr ten interface:

class Communication
{
public:
     explicit Communication(std::unique_ptr<IClient> && client);

     … … …
};

Potem implementujesz TcpClient jako konkretyzację IClient, oraz równocześnie piszesz Mock-a dla IClient, że by potem pisać testy (polecam gmock).

class MockClient
{
public:
    MOCK_METHOD2(connect, int(const std::string& addr, int port));
    MOCK_METHOD0(disconnect, int);
    MOCK_METHOD1(write, int(const std::vector<char>& data));
    MOCK_METHOD1(read, int(std::vector<char>& data));
};

Disclaimer: można się też zastanowić czy nie warto podzielić tego interfacu, na dwie części i użyć wzorca fabryki.
Wówczas connect byłą by metodą fabrykująca.
Disclaimer2: te twoje nazwy nie są zbyt trafione.

1 użytkowników online, w tym zalogowanych: 0, gości: 1