Turniej rycerski w Siewierzu

Dziś postanowiłem odwiedzić Siewierz, bo ciekawiło mnie, jak w praktyce wyglądają turnieje rycerskie, a także chciałem zobaczyć zamek w Siewierzu. Muszę przyznać, że spodziewałem się, iż zamek wygląda bardziej okazałe, jednakże faktycznie można go nazwać tylko ruinami. Dowiedziałem się jednak, że zamek wcześniej wyglądał znacznie gorzej, wejście na dziedziniec było niedostępne  zabarykadowane, podczas gdy obecnie został w znacznej części odrestaurowany.

Należy przyznać, że impreza była dobrze zorganizowana, a najprawdopodobniej wynikało to z co najmniej kilkuletniej tradycji. Oprócz potyczek rycerskich można było postrzelać z łuku, zjeść dobrą kiełbasę i popić dobre piwo, ale tym ostatnim niezbyt byłem zainteresowany 😛

Na błoniach rozbite było pole namiotowe. Po samym polu – oprócz rycerzy – spacerowały niewiasty, łucznicy oraz panowie wyglądający na kmiotów. Wszystko odbywało się przy akompaniamencie zgrzytu mieczy, nastrojowej muzyki i… piorunów, ponieważ w godzinach popołudniowych nadszedł ulewny deszcz i zerwała się burza. Uważam, że warto pojechać do Siewierza jeszcze raz 🙂

Poniżej fotorelacja – żałuję jednak, że nie mogłem przebywać na wieży dłużej niż kilkadziesiąt sekund, ponieważ kustosz opiekujący się obiektem na widok chmur burzowych wszystkich zgonił z wieży, mówiąc, że piorunochron stoi nie bez przyczyny, a wieża będąc najwyższym punktem w okolicy nie jest miejscem bezpiecznym 🙂

Wzorzec obserwator C++/Qt

Często się zdarza że programiści napotykają problem we współczesnych programu posiadające interfejs użytkownika (GUI), muszą reagować na zmiany danych w kilku różnych miejscach jednocześnie. Do sytuacji takiej może dojść wtedy gdy pracujemy na tych samych danych, które możemy edytować w kilku miejscach jednocześnie np. wykresy obrazujące takie same dane. Zmiana wartości na jednym wykresie implikuje zmianę wartości na pozostałych wykresach.

W przypadku kiedy mamy do czynienia z kilkoma obiektami możemy wykorzystać mechanizm sygnałów i slotów w Qt, jednak jeżeli jednak liczba obserwowanych obiektów, które się zmieniają nie jest zdefiniowana lub dotyczy znacznej grupy obiektów możemy zbudować osobną klasę zwaną Obserwatorem mającą na celu powiadamianie obiektów o występujących zmianach.

Pomimo że istnieje wiele różnych implementacji tego samego wzorca mają one elementy wspólne takie jak:

Wszystkie z obiektów można podzielić na dwie osobne grupy wydawców i klas pełniących rolę obserwatorów
Każda z implementacji zakłada że jest jeden obiekt, które informuje inne obiekty o zmianach
Mechanizm wysyłania informacji do pozostałych klas jest zdefiniowany w całości w klasie bazowej wydawcy.

Zalety i wady

Zalety:

Luźna zależność między obiektem obserwującym i obserwowanym. Ponieważ nie wiedzą one wiele o sobie nawzajem, mogą być niezależnie rozszerzane i rozbudowywane bez wpływu na drugą stronę.
Relacja między obiektem obserwowanym a obserwatorem tworzona jest podczas wykonywania programu i może być dynamicznie zmieniana.
Możliwość zablokowania klientowi drogi do bezpośredniego korzystania ze złożonego systemu, jeśli jest to konieczne.

Wady:

Obserwatorzy nie znają innych obserwatorów, co w pewnych sytuacjach może wywołać trudne do znalezienia skutki uboczne.
Zastosowanie

Wzorzec Obserwatora sprawdza się wszędzie tam, gdzie stan jednego obiektu uzależniony jest od stanu drugiego obiektu.

Implementacja

//Obserwator:
class Obserwator {
public:
    virtual void update() = 0;
};
//Obserwowany:

class Obserwowany {
protected:
    std::list <Obserwator*> obserwatorzy;
public:
    void dodaj(Obserwator *o) {
        obserwatorzy.push_back (o);
    }
    void usun(Obserwator *o) {
        obserwatorzy.remove (o);
    }
 
    void powiadom () {
        std::list<Obserwator *>::iterator it;
        for (it = obserwatorzy.begin(); it != obserwatorzy.end(); it++) {
            (*it)->update ();
        }
    }
};

Obserwowany Konkretny:

Dziedziczenie wielokrotne dostępne w C++ jest często używane w wzorcu Obserwatora

class Miod {
protected:
    int ilosc;
public:
    Miod (int q) {
        ilosc = q;
    }
 
    int pobierzIlosc () {
        return ilosc;
    }
 
    void ustawIlosc (int q) {
        ilosc = q;
    }
};
 
class ObserwowanyMiod : public Obserwowany, public Miod {
    std::string stan;
public:
    ObserwowanyMiod (int q) : Miod(q) {
    }
 
    std::string pobierzStan () {
        return stan;
    }
 
    void ustawStan (const std::string& s) {
        stan = s;
        std::cout << "Stan: " << stan << std::endl;
        powiadom();
    }
};

Obserwator Konkretny:

class ObserwatorMis : public Obserwator {
protected:
    int misId;
    ObserwowanyMiod *miod;
public:
    ObserwatorMis (ObserwowanyMiod *h, int id) {
        miod = h;
        misId = id;
    }
    void update () {
        std::string stan = miod->pobierzStan();
        if (!stan.compare ("Sa ludzie blisko miodu")) {
            std::cout << "Mis" << misId << ": Czekam w ukryciu" << std::endl;
        } else if (!stan.compare ("Nie ma ludzi blisko miodu")) {
            std::cout << "Mis" << misId << ": Kradne miod" << std::endl;
            miod->ustawIlosc(miod->pobierzIlosc()-1);
        } else if (!stan.compare ("Ida ludzie")) {
            std::cout << "Mis" << misId << ": Uciekam" << std::endl;
        }
    }
};

Przykład użycia:

int main() {
    ObserwowanyMiod miod (5);
    Obserwator *mis1 = new ObserwatorMis(&miod, 1);
    Obserwator *mis2 = new ObserwatorMis(&miod, 2);
 
    miod.dodaj(mis1);
    miod.dodaj(mis2);
 
    std::cout << "Ilosc miodu: " << miod.pobierzIlosc() << std::endl;
 
    miod.ustawStan("Sa ludzie blisko miodu");
    miod.ustawStan("Nie ma ludzi blisko miodu");
    miod.ustawStan("Ida ludzie");
 
    std::cout << "Ilosc miodu: " << miod.pobierzIlosc() << std::endl;
    delete mis1;
    delete mis2;
    return 0;
}

Pytania rekruterów na stanowisko C++/Qt Developer.

1. Co to jest dziedziczenie?
2. Czym jest polimorfizm?
3. Jakie znasz wzorce strukturalne?
5. Do czego służy rzutowanie?
6. Czy język C++ jest językiem obiektowym?
7. Co to jest kompilacja?
8. Czym jest linkowanie?
9. Co to jest zmienna statyczna?
10. Czym jest zakres funkcji?
11. Jak możemy przekazywać parametry do funkcji?
12. Czym jest przeciążenie funkcji?
13. Czym jest przeładowanie operatorów?
14. Czym jest funkcja wirtualna?
15. Co oznaczają słowa private, protected?
16. Co oznacza słówko const?
17. Czym są sygnały i sloty?
18. Na czym polega płytkie kopiowanie?
19. Czym są inteligentne wskaźniki?
20. Jaka różnica jest pomiędzy stosem a stertą?
21. Czym jest funkcja statyczna?
22. C++ 11 : typ auto, wyrażenia lambda, wielowątkowość.
22. Czym są mutexy?
23. Do czego służą szablony funkcji?
24. Czym są wycieki pamięci?
25. Czym są kontenery?
26. Na czym polega rekurencja?
27. Czym jest typ wyliczeniowy?
28. Co oznacza słówko inline?
29. Czym jest refraktoryzacja?
30. Czym jest konstruktor i destruktor?
31. Do czego służy destruktor wirtualny?
32. Czy konstruktor może być wirtualny?
33. Czym jest lista inicjalizacyjna?

Jak są jakieś propozycje pytań to proszę w komentarzach. Dopiszę do listy 😉

a więc dopisane do listy:

34. Czym jest inkrementacja, a czym dekrementacja?
35. Co powoduje słówko explicit przed konstruktorem?
36. Do czego służy profiler?

Recenzja filmu Pitbul. Nowe oblicze

Film nakręcony przez Patryka Vegę ma w sobie element wartkiej akcji, dający wrażenie kręconego z rozmachem widowiska.

Produkcję można zaliczyć do lepszych dzieł, inspirowanych legendami o polskim półświatku przestępczym. Zaletą filmu może być wielowątkowość i mnogość bohaterów oraz odgrywanych przez nich ról, bo każda jest bardzo wyrazista i kontrowersyjna na swój sposób 🙂 Film warto obejrzeć ze względu na wiele sensacyjnych motywów i scen. Pokazuje pracę polskiej policji w warunkach ekstremalnego stresu, układów i wewnętrznych pobudek lub ich braku ( statystyka nie rozgranicza przestępców na małych i dużych, prawie jak w Sosnowcu 🙂 ).

Film dla osób o mocnych nerwach.

Moja ocena to 8/10 Ocena ✭✭✭✭✭✭✭✰✰

Wzorzec Adapter C++/Qt

Zastosowanie

Adapter inaczej nazywany Nakładką (ang. wrapper) to strukturalny wzorzec projektowy, którego zadaniem jest stworzenie spójnego interfejsu dla dwóch niekompatybilnych klas. Adapter przekształca interfejs jednej z klas na interfejs drugiej.

Adapter

Wskazówki praktyczne

Aby stworzyć wspólny interfejs warto zaimplementować klasę z metodami wirtualnymi która będzie częścią wspólną dla niewspółbieżnych klas. Adapter jest używany w przypadku gdy chcemy przysłonić już istniejące interfejsy jednym wspólnym, a nie możemy tego zrobić np. w sytuacji używania bibliotek zewnętrznych do których mamy tylko API. Autorzy często przytaczają przykład różnych wejść (HDMI, VGA) które mają takie same zadania ale różne interfejsy, a klient ma obsługiwać takie same metody (wyświetl, odepnij).

Zalety i wady

Zalety

  • Umożliwia współprace klas których wykorzystanie byłoby utrudnione ze względu na brak spójnych interfejsów.
  • Bardziej przejrzysty kod

Wady:

  • Wymagane jest dziedzicznie co powoduje przyrost plików z klasami (jeżeli stosujemy adapter klasowy)
  • Adapter klasowy jest mniej elastyczny niż Adapter obiektowy np. po dodaniu w naszym przykładzie getScreenShot(), zakrywanie metod wirtualnych jest bezsensowne w przypadku Mp3Player
#include <QDebug>
#include <QString>

class Player
{
    public:
        virtual void play(){}
        virtual void stop(){}
};

class FlashPlayer: public Player
{
    public:
        void play(){ qDebug() << "Play flash file"; }
        void stop(){ qDebug() << "Stop flash file"; }
};

// This is liblary and we cannot change implementatnion
class Mp3Player
{
    public:
        void playSound(){ qDebug() << "Play mp3 file"; }
        void stopSound(){ qDebug() << "Stop mp3 file"; }
};

/* Adapter */
class Mp3Adapter : public Mp3Player, public Player
{
public:
    void play(){playSound();}
    void stop(){stopSound();}

};

int main()
{
    Player *flash = new FlashPlayer();
    //  Player *mp3 = new Mp3Player();  // Błąd !!!
      Player *mp3 = new Mp3Adapter();

    QList <Player *> listPlayers{flash,mp3};

    foreach(Player *play, listPlayers)
        play->play();


    foreach(Player *play, listPlayers)
        play->stop();

    qDeleteAll(listPlayers);

    return 0;
}

Wyjście programu:

Play flash file
Play mp3 file
Stop flash file
Stop mp3 file

Wzorzec Fabryka abstrakcyjna i Metoda wytwórcza C++/Qt

Zastosowanie

Fabryka abstrakcyjna (ang. abstract factory) to kreacyjny wzorzec metody wytwórczej dostarcza abstrakcji do tworzenia obiektów nieokreślonych, ale powiązanych typów. Umożliwia także dziedziczącym klasom decydowanie jakiego typu ma to być obiekt. Jest on często używany wraz ze wzorce metody wytwórczej lub inaczej nazywanej metody fabrykującej (ang. factory method), która umożliwia zwracanie obiektów, lub przypisywanie im właściwości w zależności od parametru wysłanego.

Fabryka abstrakcyjna

Wskazówki praktyczne

Wzorzec jest stosowany wówczas gdy chcemy ujednolicić interfejs i uniezależnić interfejs od implementacji i składania obiektów. W przypadku metody wytwórczej stosujemy ją wówczas gdy nie wiemy jakie obiekty będą tworzone podczas używania programu (np. będzie delegatem lub tworzona przez wybór użytkownika). Dobrym przykładem jest generowania poprzez klasy konkretne plików html, pdf lub zwykłego tekstu, za pomocą wspólnego interfejsu (fabryki abstrakcyjnej).

Zalety i wady

Zalety

  • Odseparowanie klas konkretnych poprzez posługiwanie się interfejsami abstrakcyjnymi.
  • Łatwość rzutowania pomiędzy obiektami pochodnymi.
  • Spójność klas, w sytuacji gdy pożądane jest, aby klasy produkty były z określonej rodziny, fabryka bardzo dobrze to zapewnia.
  • Łatwość utrzymania kodu po dodaniu klasy pochodnej, oraz łatwe dodawanie implementacji logiki nowych klas pochodnych.

Wady:

  • Trudność w rozszerzaniu o nowe funkcjonalności klas pochodnych, spowodowana koniecznością rozszerzania interfejsów fabryki.
#include <QDebug>
#include <QString>

using namespace std;

// Abstract base class
class Oferta {
public:
    virtual const QString getOfertaPodstawowa() = 0;
    virtual const QString getDodatki() = 0;

    void print() {
        qDebug() << getOfertaPodstawowa() <<  getDodatki();
    }
    virtual ~Oferta(){qDebug() <<"Oferta usunięta";}

};

// Klasa konkretna
class OszczednaOferta : public Oferta {
public:
   const QString getOfertaPodstawowa() {
        return "Abonament 20zł";
    }

   const QString getDodatki() {
        return "Pakiet 60 minut i 30 sms-ów";
    }
   ~OszczednaOferta(){ qDebug() <<"Oszczędna oferta usunięta"; }
};

// Klasa konkretna
class SredniaOferta : public Oferta {
public:
    const QString getOfertaPodstawowa()
    {
        return "Abonament 50zł";
    }

   const QString getDodatki()
   {
        return "Pakiet 1000 minut i 1000 sms-ów";
    }
   ~SredniaOferta(){ qDebug() <<"Średnia oferta usunięta";}
};

// Klasa konkretna
class DrogaOferta : public Oferta {
public:
   const QString getOfertaPodstawowa() {
        return "Abonament 40zł";
    }

   const QString getDodatki() {
        return "Pakiet 300 minut i 200 sms-ów";
    }
   ~DrogaOferta(){ qDebug() <<"Droga oferta usunięta";}
};

// Abstract Factory returning a Oferta
class OfertaFactory {
public:
    Oferta* getOferta(const QString type)
    {
        if ( type == "Oszczędna" ) return new OszczednaOferta();
        else if ( type == "Średnia" ) return new SredniaOferta();
        else if ( type == "Droga" ) return new DrogaOferta();
        return NULL;
    }
    ~OfertaFactory(){

}

};

int main()
{
    OfertaFactory* myFactory = new OfertaFactory();

    Oferta* myOferta1 = myFactory->getOferta("Oszczędna");
    myOferta1->print();

    Oferta* myOferta2 = myFactory->getOferta("Średnia");
    myOferta2->print();

    Oferta* myOferta3 = myFactory->getOferta("Droga");
    myOferta3->print();

    delete myOferta1;
    delete myOferta2;
    delete myOferta3;

    return 0;
}

Wyjście programu:

"Abonament 20zł" "Pakiet 60 minut i 30 sms-ów"
"Abonament 50zł" "Pakiet 1000 minut i 1000 sms-ów"
"Abonament 40zł" "Pakiet 300 minut i 200 sms-ów"
Oszczędna oferta usunięta
Oferta usunięta
Średnia oferta usunięta
Oferta usunięta
Droga oferta usunięta
Oferta usunięta

Przykład 2

#include <iostream>
#include <QtCore>


using namespace std;

class Shape {
  public:
    Shape() {
      id_ = total_++;
    }
    virtual void draw() = 0;
  protected:
    int id_;
    static int total_;
};
int Shape::total_ = 0;

class Circle : public Shape {
  public:
    void draw() {
      cout << "circle " << id_ << ": draw" << endl;
    }
};
class Square : public Shape {
  public:
    void draw() {
      cout << "square " << id_ << ": draw" << endl;
    }
};
class Ellipse : public Shape {
  public:
    void draw() {
      cout << "ellipse " << id_ << ": draw" << endl;
    }
};
class Rectangle : public Shape {
  public:
    void draw() {
      cout << "rectangle " << id_ << ": draw" << endl;
    }
};

class Factory {
  public:
    virtual Shape* createCurvedInstance() = 0;
    virtual Shape* createStraightInstance() = 0;
};

class SimpleShapeFactory : public Factory {
  public:
    Shape* createCurvedInstance() {
      return new Circle;
    }
    Shape* createStraightInstance() {
      return new Square;
    }
};
class RobustShapeFactory : public Factory {
  public:
    Shape* createCurvedInstance()   {
      return new Ellipse;
    }
    Shape* createStraightInstance() {
      return new Rectangle;
    }
};

int main() {
#ifdef Q_OS_LINUX
  Factory* factory = new SimpleShapeFactory;
#elif Q_OS_ANDROID
  Factory* factory = new RobustShapeFactory;
#endif
  Shape* shapes[3];

  shapes[0] = factory->createCurvedInstance();   // shapes[0] = new Ellipse;
  shapes[1] = factory->createStraightInstance(); // shapes[1] = new Rectangle;
  shapes[2] = factory->createCurvedInstance();   // shapes[2] = new Ellipse;

  for (int i=0; i < 3; i++) {
    shapes[i]->draw();
  }
  for (int i=0; i < 3; i++)
    delete shapes[i];
}