Narzędzia użytkownika

Narzędzia witryny


nvi
// 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
	}
};
nvi.txt · ostatnio zmienione: 2008/04/15 13:07 przez 3p