Narzędzia użytkownika

Narzędzia witryny


nvi

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

nvi [2008/04/15 13:07] (aktualna)
3p utworzono
Linia 1: Linia 1:
 +<code cpp>
 +// Paweł Pawliński E1ISI //
 +//                       //
 +////////////////////////////////////////////////////////////////​
 +//
 +//            Wzorzec Non-virtual Interface (NVI)
 +//
 +////////////////////////////////////////////////////////////////​
 +
 +// Wzorzec NVI pozwala na oddzielenie interfejsu od szczegółów implementacji,​
 +// które można modyfikować dzięki dziedziczeniu i polimorfizmowi.
 +// Główny pomysł opiera się na unikaniu deklarowania funkcji wirtualnych
 +// jako publicznych.
 +
 +#include <​string>​
 +#include <​vector>​
 +#include <​exception>​
 +
 +// Przykładowa klasa bazowa CommInterface,​ implementująca NVI:
 +class CommInterface {
 +public:
 + // Wszystkie metody publiczne nie są wirtualne, dzięki czemu zawsze
 + // będą wywoływane metody klasy CommInterface.
 + void shutdown () throw (std::​exception) {
 +
 + // doShutdown to prywatna metoda czysto wirtualna.
 + doShutdown ();
 +
 + // Dzięki temu, że nasz interfejs jest niewirtualny,​ możemy
 + // zagwarantować pewną funkcjonalność i jednocześnie nie 
 + // wymuszać na autorze klasy pochodnej jej implementacji,​ np.
 + // możemy zagwarantować spełnienie pewnych warunków:
 + if (not queue.empty()) throw(std::​exception());​
 + }
 +
 + // Wzorzec NVI jest silnie związany z wzorcem metody szablonu
 + // (template method pattern). W skrócie sprowadza się on do
 + // umieszczenia w metodzie klasy bazowej schematu algorytmu, którego
 + // kolejne kroki są wywołaniami prywatnych funkcji wirtualnych.
 + // Prostym przykładem może być poniższe zapytanie:
 + std::​string&​ query (std::​string &q) {
 +
 + validateInput(q);​ //​ krok 1
 + send(q);​ //​ krok 2
 + std::​string&​ results = recieve();​ //​ krok 3
 + validateOutput(results);​ //​ krok 4
 +
 + return results;
 + }
 +
 + // Destruktory są wyjątkiem - muszą być zadeklarowane jako wirtualne
 + // (konieczne do poprawnego niszczenia obiektów klas pochodnych) oraz
 + // posiadać dostęp publiczny.
 + virtual ~CommInterface () {
 + // W przypadku klasy CommInterface brak operacji.
 + }
 +
 +protected:
 + // Przykładowa kolejka wychodząca.
 + std::​vector<​std::​string>​ queue;
 +
 +private:
 + // W tym przykładzie wszystkie funkcje wirtualne z wyjątkiem
 + // destruktorów zadeklarowane są jako nie-publiczne.
 + // Poniżej znajdują się przykładowe "​prymitywne"​ funkcje,
 + // reprezentujące szczegóły implementacji,​ o które klasa bazowa
 + // pozostawia do implementacji klasom pochodnym.
 +
 + // Wysłanie danych z kolejki i zamknięcie połączenia
 + virtual void doShutdown () throw () = 0;
 +
 + // Wysłanie danych z kolejki
 + virtual void send (std::​string &) = 0;
 +
 + // Odebranie danych
 + virtual std::​string&​ recieve () = 0;
 +
 +protected:
 + // Zadeklarowanie metod jako protected pozwala klasom pochodnym
 + // skorzystanie z gotowych implementacji w klasie bazowej, co może
 + // być bardzo przydatne np. przy serializacji.
 +
 + // Walidacja wyjścia od zdalnego serwera
 + virtual void validateOutput (std::​string s) throw (std::​exception) {
 +
 + if (s.size() < 1024) throw (std::​exception());​
 + }
 +
 + // Walidacja wejścia od użytkownika
 + virtual void validateInput (std::​string s) throw (std::​exception) {
 +
 + if (s.size() == 0) throw (std::​exception());​
 + }
 +};
 +
 +
 +// Przykładowa konkretne klasa pochodna, implementująca funkcje czysto
 +// wirtualne.
 +class CommViaTLS : public CommInterface {
 +public:
 + // W sekcji publicznej nie ma potrzeby implementowania metod klasy
 + // bazowej.
 +
 +private:
 +
 + // Przykładowe implementacje.
 +
 + virtual void doShutdown () throw () {
 +
 + while (!queue.empty()) {
 + send(queue.back());​
 + queue.pop_back();​
 + }
 +
 + // Tu powinno nastąpić np. zamknięcie sesji TLS.
 + // close() ...
 + }
 +
 + virtual void send (std::​string &) {
 +
 + // Tu powinno nastąpić wysłanie danych.
 + // write(...)
 +
 + queue.pop_back();​
 + }
 +
 +
 + virtual std::​string&​ recieve () {
 +
 + // Tu powinno znajdować się czytanie z deskryptora
 + // read(...)
 + }
 +};
 +
 +// W innych klasach możemy implementować pozostałe funkcje wirtualne - fakt, że
 +// niektóre nie są czysto wirtualne, sygnalizuje domyślną implementację,​ którą
 +// można zmodyfikować.
 +class CommViaDBUS : public CommInterface {
 +private:
 +
 + virtual void doShutdown () throw () {
 +
 + // ...
 + // miejsce na konkretną implementację
 + }
 +
 + virtual void send (std::​string &) {
 +
 + // ...
 + // miejsce na konkretną implementację
 + }
 +
 + virtual std::​string&​ recieve () {
 +
 + // ...
 + // miejsce na konkretną implementację
 + }
 +
 + virtual void validateInput (std::​string s) throw (std::​exception) {
 +
 + CommInterface::​validateInput(s);​
 + // ...
 + // Tu powinna nastąpić dodatkowa walidacja
 + }
 +
 + virtual void validateOutput (std::​string s) throw (std::​exception) {
 +
 + CommInterface::​validateOutput(s);​
 + // ...
 + // Tu powinna nastąpić dodatkowa walidacja
 + }
 +};
 +</​code>​
  
nvi.txt · ostatnio zmienione: 2008/04/15 13:07 przez 3p