Projektowanie klas i programowanie obiektowe na przykładzie aplikacji do przetwarzanie tekstu.
Poniżej został zaprezentowany szkielet aplikacji do przetwarzania tekstu, który będzie rozbudowywany i omawiany wraz z nowymi laboratoriami. Przedstawiane zagadnienia będą obejmowały zawansowane aspekty programowania w c++. Czytelnicy nabiorą biegłości w wykorzystaniu biblioteki standardowej STL oraz Boost. Zapoznają się z szablonami oraz metodami projektowania klas. Wszytko zostanie przedstawione na podstawie projektowania i implementacji programu do przetwarzania tekstu.
Poniżej zaprezentowano interfejsy jak i ich implementacja klas które będą omawiane, refaktoryzowane i stosowane podczas omawiania ww. materiału. Podstawowy szkielet aplikacji składa się z następujących plików:
– agencyText.cpp – zawiera kod wykonawczy programu oraz testy zaprojektowanych i zaimplementowanych interfejsów,
– textAgent.h oraz textAgent.cpp – interfejs oraz jego implementacja do rejestrowania i użytkowania modułu do przetwarzania tekstu,
– textTool.h oraz textTool.cpp – interfejs oraz jego implementacja do przetwarzania strumienia tekstowego.
Kod aplikacji wykorzystujący utworzone interfejsy przedstawia listing poniżej:
agencyText.cpp
//============================================================================
// Name : agencyText.cpp
// Author : Marcin Mirończuk
// Version : 1.0
// Copyright : GPL
// Description : The agency to text retrive
//============================================================================
/**
* Rejestracja bibliotek
*/
#include <iostream>
#include <string>
#include <vector>
#include "textAgent.h"
/**
* Rejestracja przestrzeni nazw
*/
using namespace std;
using namespace ta;
/**
* Program glowny
*/
int main() {
/**
* Wystartowanie kilku agentow dynamicznych oraz statycznych, nazwanych jak i nienazwanych (anonimowych)
*/
ta::textAgent agentStatyczny(1220, 1, "przetwarzacz tekstu 1", "Agent T1");
ta::textAgent niezweryfikowanyAgentStatyczny;
textAgent *agentDynamiczny = new textAgent(12330, 2, "przetwarzacz tekstu 2", "Agnet T2");
textAgent *niezweryfikowanyAgentDynamiczny = new textAgent();
try {
/**
* Pokazanie informacji o rezydujacych agentach
*/
cout << "Zarejestrowany agent i jego dane:" << endl;
agentStatyczny.showData();
cout << endl;
cout << "Agent oczekujacy na rejestracje:" << endl;
niezweryfikowanyAgentStatyczny.showData();
cout << endl;
cout << "Agent dynamiczny zarejstrowany:" << endl;
agentDynamiczny->showData();
cout << endl;
cout << "Agent dynamiczny niezweryfikowany:" << endl;
niezweryfikowanyAgentDynamiczny->showData();
cout << endl;
/**
* Rejestracja modulu (przybornika) do przetwarzania tekstow
*/
tt::textTool tt;
/**
* Rejestracja przybornika dla agenta dynamicznego
*/
agentDynamiczny->rejestrTextTool(tt);
agentDynamiczny->rejestrTextTool().extractSegments("Ala ma kota.");
cout << "Ilosc zliczonych segmentow: " << agentDynamiczny->rejestrTextTool().getCountSegments() << endl;
cout << "Pokaz jakie segmenty zliczyles: " << endl;
agentDynamiczny->rejestrTextTool().showSegments();
cout << endl;
/**
* Rejestracja przybornika dla agenta statycznego
*/
agentStatyczny.rejestrTextTool(tt);
agentStatyczny.rejestrTextTool().extractSegments("A ja mam kota. I wiecej tekstu.");
cout << "Ilosc zliczonych segmentow: " << agentStatyczny.rejestrTextTool().getCountSegments() << endl;
cout << "Pokaz jakie segmenty zliczyles: " << endl;
agentStatyczny.rejestrTextTool().showSegments();
cout << endl;
cout << "Testowanie usowania spacji:" << endl;
std::string testString1 = " kota ";
cout << "- Tekst przed filtracja: " << testString1 << endl;
cout << "- Filtracja: " << "Tekst odfiltrowany: " << agentStatyczny.rejestrTextTool().stripWhiteSpace(testString1) << endl;
cout << "- Filtracja: " << "Tekst pierwotny " << testString1 << endl;
std::string *pTestString1 = &testString1;
cout << "- Tekst przed filtracja wskaznik / zmienna: " << *pTestString1 << " / " << testString1 << endl;
agentStatyczny.rejestrTextTool().stripWhiteSpace(pTestString1);
cout << "- Filtracja: " << "Tekst odfiltrowany " << *pTestString1 << endl;
cout << "- Filtracja: " << "Tekst pierwotny " << testString1 << endl;
cout << endl;
cout << "Testowanie tokenizacji:" << endl;
std::string testString2 = "Ala ma kota. A kot ma na imie Ala.";
cout << "- Tekst podlegajacy tokenizacji: " << testString2 << endl;
agentStatyczny.rejestrTextTool().tokenize(testString2);
cout << "- Ilosc tokenow: " << agentStatyczny.rejestrTextTool().getCountTokens() << endl;
cout << "- Ilosc unikatowych tokenow: " << agentStatyczny.rejestrTextTool().getCountUniqueTokens();
delete niezweryfikowanyAgentDynamiczny;
delete agentDynamiczny;
} catch (std::string exception) {
cout<<"Wyjatek: "<< exception;
delete niezweryfikowanyAgentDynamiczny;
delete agentDynamiczny;
}
return 0;
}
Interfejs agenta który rejestruje moduł do przetwarzania tekstu i za pośrednictwem którego odbywają się wszelkie modyfikacja przedstawia listing poniżej:
/*
* textAgent.h
*
* Created on: 21-12-2011
* Author: Marcin Mirończuk
* Licenc: GPL
*
* Klas modelujaca podstawowe elementy agenta do przetwarzania tekstu.
* Agent ma mozliwosc rejestrowania u siebie modulu do przetwarzania tekstu za omoca ktorego przetwarza tekst.
*
*/
#include <string>
#include "textTool.h"
#ifndef TA_H_
#define TA_H_
/**
* Definicja przestrzeni nazw
*/
namespace ta {
/**
* Definicja klasy
*/
class textAgent {
/**
* Skladowe i metody prywatne klasy
*/
private:
/**
* @type int timeCreate Czas w sekundach Unix timestamp
*/
int timeCreate;
/**
* @type float priority Priorytet agebta
*/
int priority;
/**
* @type string task Zadanie/praca do wykonania przez agebta
*/
std::string task;
/**
* @type string name Nazwa agenta
*/
std::string name;
/**
* @type bool isTextTool Flaga rejestracji modulu tekstu
*/
bool isTextTool;
/**
* @type textTool textTool Uchwyt do modulu przetwarzajacego tekst
*/
tt::textTool textTool;
/**
* Skladowe i metody publiczne klasy
*/
public:
/**
* Konstruktor podstawowy domyslny
*/
textAgent();
/**
* Konstruktor rozszerzony
*/
textAgent(float ptimeCreate, float ppriority, std::string ptask, std::string pname);
/**
* Pobranie wieku agenta
*
* @return float
*/
int getTimeCreate();
/**
* Pobranie wagi agenta
*
* @return float
*/
int getPriority();
/**
* Pobranie zadania agenta
*
* @return string
*/
std::string getTask();
/*
* Pobranie nazwy agenta
*
* @return string
*/
std::string getName();
/**
* Pokazanie danych o agencie
*
* @return void
*/
void showData();
/**
* Rejestracja modulu do przetwarzania tekstu
*
* @return tt::textTool
*/
const tt::textTool & rejestrTextTool(tt::textTool tt);
/**
* Rejestracja, pobranie modulu do przetwarzania tekstu
*
* @return tt::textTool
* @thorw exception
*/
tt::textTool & rejestrTextTool();
/**
* Destruktor
*/
virtual ~textAgent();
};
} /* namespace textagent */
#endif /* TA_H_ */
Interfejs programu (modułu) do przetwarzania strumienia danych tekstowych przedstawia listing poniżej:
/*
* textAgent.cpp
*
* Created on: 21-12-2011
* Author: Marcin Mirończuk
* Licenc: GPL
*
* Implementacja interfejsu agenta do przetwarzania tekstu @see textAgent.h
*
*/
#include <iostream>
#include "textAgent.h"
#include "textTool.h"
namespace ta {
textAgent::textAgent() {
this->timeCreate = 0;
this->priority = 0;
this->task = "unknown";
this->name = "inkognito";
this->isTextTool = false;
}
textAgent::textAgent(float ptimeCreate, float ppriority, std::string ptask, std::string pname) {
this->timeCreate = ptimeCreate;
this->priority = ppriority;
this->task = ptask;
this->name = pname;
this->isTextTool = false;
}
int textAgent::getTimeCreate() {
return this->timeCreate;
}
int textAgent::getPriority() {
return this->priority;
}
std::string textAgent::getTask() {
return this->task;
}
std::string textAgent::getName() {
return this->name;
}
void textAgent::showData() {
std::cout << "Time create: " << this->timeCreate << std::endl;
std::cout << "Priority: " << this->priority << std::endl;
std::cout << "Name: " << this->name << std::endl;
std::cout << "Task: " << this->task << std::endl;
}
const tt::textTool & textAgent::rejestrTextTool(tt::textTool tt) {
if(this->isTextTool == false) {
this->textTool = tt;
this->isTextTool = true;
return this->textTool;
} else {
return this->textTool;
}
}
tt::textTool & textAgent::rejestrTextTool() {
if(this->isTextTool == false) {
std::string exception = "Unregister text tool!";
throw exception;
} else {
return this->textTool;
}
}
textAgent::~textAgent() {
}
} /* namespace ta */
Implementację interfejsu programu do przetwarzania tekstu zawiera listing poniżej:
/*
* textTool.h
*
* Created on: 21-12-2011
* Author: Marcin Mirończuk
* Licenc: GPL
*
* Klas modelujaca modul (przybornik) do przetwarzania tekstu.
*
*/
#include <map>
#include <vector>
#include <string>
#ifndef TT_H_
#define TT_H_
/**
* Definicja przestrzeni nazw
*/
namespace tt {
/**
* Definicja klasy
*/
class textTool {
/**
* Skladowe i metody prywatne klasy
*/
private:
/**
* @type vector<string> segment Wektor segmentow
*/
std::vector<std::string> segments;
/**
* @type vector<string> tokens Wektor tokenow (wyrazen)
*/
std::vector<std::string> tokens;
/**
* @type vector<string> uniqueTokens Wektor unikalnych tokenow (wyrazen)
*/
std::vector<std::string> uniqueTokens;
/**
* @type vector<string, int> tokensFrequ Tablica klucz=wartosc czestotliwosci wyrazen
*/
std::map<std::string, int> tokensFrequ;
/**
* Usowanie duplikatow wyrazen z wektora wyrazen
*
* @see http://learningcppisfun.blogspot.com/2008/04/remove-duplicates-from-vector.html
* @see http://stackoverflow.com/questions/1041620/most-efficient-way-to-erase-duplicates-and-sort-a-c-vector
*
* @param vector<string> vec
*
* @return vector<string>
*/
std::vector<std::string> removeDuplicates(std::vector<std::string> vec);
public:
/**
* Domyslny konstruktor
*/
textTool();
/**
* Wydobywanie segmentow z tekstu.
*
* @param string &text
*
* @return vector<string>
*/
std::vector<std::string> extractSegments(const std::string &text);
/**
* Pobranie ilosci wydobytych segmentow z tekstu.
*
* @return int
*/
int getCountSegments();
/**
* Pokazanie wydobytych segmentow z tekstu.
*
* @return void
*/
void showSegments();
/**
* Usuniecie spacji z poczatku jak i z konca lancucha znakow.
*
* @param string text
*
* @return string
*/
std::string stripWhiteSpace(std::string text);
/**
* Przeciazona wersja usuniecia spacji z poczatku jak i z konca lancucha znakow.
*
* @param string *text
*
* @return void
*/
void stripWhiteSpace(std::string *text);
/**
* Kalkulacja, wyznaczanie macierzy czetotliwosci wystepowania wyrazen w pojedynczym dokumencie tekstowym.
*
* @param string &text
*
* @return map<string, int>
*/
std::map<std::string, int> computeTokensFrequ(const std::string &text);
/**
* Tokenizacja tekstu tj. rozbicie tekstu na wektor wyrazen.
* @see http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
*
* @param string &text
*
* @return vector<string>
*/
std::vector<std::string> tokenize(const std::string &text);
/**
* Pobranie ilosci wyrazen.
*
* @return int
*/
int textTool::getCountTokens();
/**
* Pobranie ilosci unikalnych wyrazen.
*
* @return int
*/
int textTool::getCountUniqueTokens();
/**
* Domyslny destruktor
*/
virtual ~textTool();
};
} /* namespace tt */
#endif /* TT_H_ */
Implementację powyżej zaprezentowanego interfejsu programu do przetwarzania tekstu zawiera listing poniżej:
/*
* textTool.cpp
*
* Created on: 21-12-2011
* Author: Marcin Mirończuk
* Licenc: GPL
*
* Implementacja interfejsu modulu do przetwarzania tekstu @see textTool.h
*
*/
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include "textTool.h"
namespace tt {
textTool::textTool() {
}
/**
* Bardzo naiwna, prezentacyja wersji algorytmu do rozbijania tekstu na segmenty (zdania)
*/
std::vector<std::string> textTool::extractSegments(const std::string &text) {
std::string tempSegment;
for(int i = 0; i < text.length(); i++) {
if(text[i] == '.' || text[i] == '?' || text[i] == '!') {
tempSegment = (std::string) tempSegment;
this->segments.push_back(this->stripWhiteSpace(tempSegment));
tempSegment.clear();
} else {
tempSegment += text[i];
}
}
return this->segments;
}
int textTool::getCountSegments() {
return this->segments.size();
}
std::string textTool::stripWhiteSpace(std::string text) {
if(text[0] == ' ') {
text.replace(0, 1, "");
}
if(text[text.length()-1] == ' ') {
text.replace(text.length()-1, 1, "");
}
return text;
}
void textTool::stripWhiteSpace(std::string *text) {
std::string::iterator it;
it = text->begin();
if(*it == ' ') {
text->replace(0, 1, "");
}
it = text->end();
if(*(it-1) == ' ') {
text->replace(text->length()-1, 1, "");
}
}
void textTool::showSegments() {
for(int i = 0; i < this->segments.size(); i++) {
std::cout << this->segments[i] << std::endl;
}
}
std::map<std::string, int> textTool::computeTokensFrequ(const std::string &text) {
this->tokenize(text);
this->removeDuplicates(this->tokens);
std::vector<std::string>::iterator it;
for (it = this->uniqueTokens.begin(); it < this->uniqueTokens.end(); it++) {
std::cout << " " << *it;
}
return this->tokensFrequ;
}
std::vector<std::string> textTool::tokenize(const std::string &text) {
// Buforowany string
std::string buf;
// Wstawienie stringu z potoku
std::stringstream ss(text);
while (ss >> buf) {
this->tokens.push_back(buf);
}
return this->tokens;
}
int textTool::getCountTokens() {
return this->tokens.size();
}
int textTool::getCountUniqueTokens() {
if(this->tokens.size() != 0 && this->uniqueTokens.size() == 0) {
this->removeDuplicates(this->tokens);
return this->uniqueTokens.size();
} else {
return this->uniqueTokens.size();
}
}
std::vector<std::string> textTool::removeDuplicates(std::vector<std::string> vec) {
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
this->uniqueTokens = vec;
return this->uniqueTokens;
}
textTool::~textTool() {
}
} /* namespace tt */