Suunnittelumallit (Design Patterns) tarjoavat vakiintuneita ja tehokkaita ratkaisuja ohjelmoinnissa esiintyviin rakenteellisiin ja käyttäytymiseen liittyviin haasteisiin. Tässä esitellään kolme yleisesti käytettyä mallia: Singleton, Observer ja Factory.
Tarkoitus: Varmistaa, että luokalla on vain yksi instanssi ja tarjoaa globaalin pääsyn siihen.
Missä käytetään: Esimerkiksi konfiguraatiohallinta, lokitusjärjestelmät tai tietokantayhteys.
+--------------------+ | Singleton | +--------------------+ | - instance: static | | - Singleton() | +--------------------+ | + getInstance() | +--------------------+
class Singleton {
private:
inline static Singleton* instance = nullptr;
Singleton() {}
string name;
public:
static Singleton* getInstance() {
if (!instance)
instance = new Singleton();
return instance;
}
string getName(){
return name;
}
void setName(string value){
name=value;
}
};
Edellisestä luokasta voidaan luoda olioita seuraavasti
Singleton* objSingleton1 = Singleton::getInstance(); objSingleton1->setName("Teppo Testi"); //edellä luodaan uusi olio Singleton* objSingleton2 = Singleton::getInstance(); //edellä ei luoda uutta oliota, vaan palautetaan olemassa oleva olio cout<<objSingleton2->getName();
Tarkoitus: Mahdollistaa monen olion reagoinnin toisen olion tilamuutoksiin.
Missä käytetään: Käyttöliittymät (UI), tapahtumakäsittely, pelitilanteet (esim. pisteytys tai tilapäivitys).
+----------------+ +--------------------+ | Subject |<----- | Observer | +----------------+ +--------------------+ | +attach(obs) | | +update() | | +setState() | +--------------------+
#include <iostream>
#include <vector>
#include <string>
class Observer {
public:
virtual void update(int value) = 0;
virtual ~Observer() = default;
};
class Subject {
int state;
std::vector<Observer*> observers;
public:
void attach(Observer* obs) {
observers.push_back(obs);
}
void setState(int s) {
state = s;
notifyAll();
}
void notifyAll() {
for (Observer* obs : observers) {
obs->update(state);
}
}
};
class ConcreteObserver : public Observer {
std::string name;
public:
ConcreteObserver(const std::string& n) : name(n) {}
void update(int value) override {
std::cout << "Observer [" << name << "] sai päivityksen: tila = " << value << std::endl;
}
};
int main() {
Subject subject;
ConcreteObserver obs1("A");
ConcreteObserver obs2("B");
subject.attach(&obs1);
subject.attach(&obs2);
std::cout << "Asetetaan tila arvoon 42...\n";
subject.setState(42);
std::cout << "Asetetaan tila arvoon 100...\n";
subject.setState(100);
return 0;
}
Tarkoitus: Tarjoaa rajapinnan olioiden luomiseen ilman, että asiakasohjelman tarvitsee tietää, mitä luokkaa käytetään.
Missä käytetään: Pelit (eri vihollistyypit), käyttöliittymäkomponenttien luonti, plugin-arkkitehtuuri.
+----------------+ +------------------------+ | Factory |-------> | Product (interface) | +----------------+ +------------------------+ | +create(type) | | +use() = 0 | +----------------+ +------------------------+ | ↑ | +----------------------+ +-----------------> | ConcreteProductA/B | +----------------------+
class Product {
public:
virtual void use() = 0;
};
class ConcreteProductA : public Product {
public:
void use() override { std::cout << "Tuote A käytössä\n"; }
};
class ConcreteProductB : public Product {
public:
void use() override { std::cout << "Tuote B käytössä\n"; }
};
class Factory {
public:
static Product* create(const std::string& type) {
if (type == "A") return new ConcreteProductA();
else if (type == "B") return new ConcreteProductB();
return nullptr;
}
};
// --- Main-funktio ---
int main() {
Product* product1 = Factory::create("A");
Product* product2 = Factory::create("B");
if (product1) {
product1->use();
delete product1;
}
if (product2) {
product2->use();
delete product2;
}
return 0;
}