/** @mainpage Dekoratorius
*
* Pirmoji užduotis objektinių technologijų kursui.
*
* Autorius: Marius Gedminas (mgedmin@@gedmin.as)
*
* VU MIF, informatika, 1M kursas, 1 grupė.
*
* 2002 m. ruduo.
*
* @section problem Problema
*
* Projektuokime dokumentų tvarkymo sistemą. Dokumentai gali būti įvairių
* rūšių (tekstas, paveiksliukai ir t.t.). Dokumentus galime peržiūrinėti,
* spausdinti, redaguoti.
*
* Taip pat norime keisti ar papildyti kai kurių konkrečių dokumentų elgesį.
* Pavyzdžiui, uždrausti kai kurių dokumentų redagavimą, ar prikabinti prie
* dokumentų anotacijas.
*
* Jei kiekvienam variantui kursime po atskirą klasę, gausime kombinatorinį
* sprogimą -- %TextDocument, ReadOnlyTextDocument, AnnotatedTextDocument,
* AnnotatedReadOnlyTextDocument ir t.t.
*
* @section solution Sprendimas
*
* Pritaikysime Dekoratoriaus šabloną. Kiekvieną dokumento tipą atitinka
* atskira klasė. Visi dokumentai paveldi iš bendros astrakčios bazinės klasės
* ir realizuoja tą patį interfeisą, nusakantį bazinį dokumentų funkcionalumą.
*
* Papildomas savybes suteiks dekoratoriai. Abstrakti dekoratoriaus klasė
* paveldi iš bazinės dokumentų klasės ir realizuoja bendrą visiems
* dekoratoriams funkcionalumą -- metodų delegavimą.
*
* Tradiciniame Dekoratoriaus šablono variante dokumentai nieko nežino apie
* dekoratorius, nežino net apie jų egzistavimą. Tačiau tokiu atveju galime
* lengvai nuimti tik išorinį dekoratorių, jei žinome jo tipą. Taip pat galime
* lengvai pasinaudoti tik išorinio dekoratoriaus (jei žinome jo tipą)
* pateikiamomis papildomomis funkcijomis, nes dekoratoriai deleguoja tik
* dokumentų interfeiso funkcijas. Norėtųsi ko nors lankstesnio.
*
* Turėdami kokį nors objektą (nežinodami, ar jis dekoruotas, ar ne), mes
* norėtumėme sužinoti (gauti nuorodą) į tam tikros konkrečios klasės
* dekoratorių (kad galėtumėme pasinaudoti jo teikiamomis papildomomis
* funkcijomis). Taip pat norėtumėme išmesti iš dekoratorių grandinės vieną
* ar visus nurodyto tipo dekoratorius.
*
* Kad pasiektumėme papildomai iškeltus tikslus turime kiek pakeisti tradicinį
* Dekoratoriaus šabloną ir pridėti kelias funkcijas į dokumentų bazinę klasę
* (negalime jų pridėti į dekoratorių bazinę klasę, nes norime ir nedekoruotus
* objektus traktuoti vienodai).
*
* @section implementation Realizacija
*
* @image html classdiagram.png "Klasių diagrama"
* @image latex classdiagram.eps "Klasių diagrama" width=12cm
*
* Klases galima sugrupuoti į tokias kategorijas:
* - @ref interfaces "Interfeisai" (@ref Document, @ref Decorator)
* - @ref documents "Konkretūs dokumentai" (@ref TextDocument, @ref Image)
* - @ref decorators "Konkretūs dekoratoriai" (@ref ReadOnly, @ref Annotation)
*
* Pagrindinėje programoje pateiktas @ref example "naudojimo pavyzdys".
*/
#include "decorator.h"
#include <iostream>
// Document
Document::~Document()
{}
// Decorator
Decorator::~Decorator()
{
delete next_;
}
// TextDocument
void TextDocument::view()
{
std::cout << "tekstinio dokumento peržiūra\n";
}
void TextDocument::print()
{
std::cout << "tekstinio dokumento spausdinimas\n";
}
void TextDocument::edit()
{
std::cout << "tekstinio dokumento redagavimas\n";
}
// Image
void Image::view()
{
std::cout << "paveiksliuko peržiūra\n";
}
void Image::print()
{
std::cout << "paveiksliuko spausdinimas\n";
}
void Image::edit()
{
std::cout << "paveiksliuko redagavimas\n";
}
// ReadOnly
void ReadOnly::edit()
{
std::cout << "negalima redaguoti šio dokumento!\n";
}
// Annotation
void Annotation::view()
{
Decorator::view();
std::cout << " anotacija: " << annotation() << '\n';
}
void Annotation::print()
{
Decorator::print();
std::cout << " anotacija: " << annotation() << '\n';
}
/**
* @addtogroup example Pavyzdys
* @{
*/
/**
* Pagrindinė programa, iliustruojanti dekoratorių panaudojimą. Ją įvykdžius
* turėtų pasirodyti šitoks tekstas:
@verbatim
* Bazinis funkcionalumas
tekstinio dokumento peržiūra
tekstinio dokumento spausdinimas
tekstinio dokumento redagavimas
paveiksliuko peržiūra
paveiksliuko spausdinimas
paveiksliuko redagavimas
* Bazinis funkcionalumas su dekoratoriais
tekstinio dokumento peržiūra
anotacija: įdomus dokumentas
tekstinio dokumento spausdinimas
anotacija: įdomus dokumentas
negalima redaguoti šio dokumento!
paveiksliuko peržiūra
anotacija: gražus paveiksliukas
anotacija: o man nepatiko
paveiksliuko spausdinimas
anotacija: gražus paveiksliukas
anotacija: o man nepatiko
paveiksliuko redagavimas
* Papildomas funkcionalumas: pakeiskime anotaciją
tekstinio dokumento peržiūra
anotacija: o gal ir nelabai įdomus
* Pereikime per visus vieno tipo dekoratorius
radau anotaciją: o man nepatiko
radau anotaciją: gražus paveiksliukas
* Nuimkime ReadOnly dekoratorių
tekstinio dokumento redagavimas
@endverbatim
*/
int main()
{
// Sukuriame plikus objektus
Document* txt = new TextDocument();
Document* img = new Image();
// Bazinis funkcionalumas
cout << "* Bazinis funkcionalumas\n";
txt->view();
txt->print();
txt->edit();
img->view();
img->print();
img->edit();
cout << '\n';
// Prikabiname dekoratorius
txt = new Annotation(txt, "įdomus dokumentas");
txt = new ReadOnly(txt);
img = new Annotation(img, "gražus paveiksliukas");
img = new Annotation(img, "o man nepatiko");
// Bazinis funkcionalumas su dekoratoriais
cout << "* Bazinis funkcionalumas su dekoratoriais\n";
txt->view();
txt->print();
txt->edit();
img->view();
img->print();
img->edit();
cout << '\n';
// Papildomas funkcionalumas
cout << "* Papildomas funkcionalumas: pakeiskime anotaciją\n";
if (Annotation* a = txt->decorator<Annotation>()) {
a->changeAnnotation("o gal ir nelabai įdomus");
txt->view();
};
cout << '\n';
// Parodykime visas anotacijas
cout << "* Pereikime per visus vieno tipo dekoratorius\n";
for (Document* tmp = img;
Annotation* d = tmp->decorator<Annotation>();
tmp = d->next())
{
std::cout << "radau anotaciją: " << d->annotation() << '\n';
}
cout << '\n';
// Nuimkime dekoratorių
cout << "* Nuimkime ReadOnly dekoratorių\n";
txt = txt->unwrap<ReadOnly>(true);
txt->edit();
cout << '\n';
// Panaikinkime objektus ir visus dekoratorius
delete txt;
delete img;
}
/// @}
syntax highlighted by Code2HTML, v. 0.9.1