State State – kontext a problém Kontext chování objektu má záviset na jeho stavu, který se typicky mění za běhu Neflexibilní řešení metody obsahují.
Download
Report
Transcript State State – kontext a problém Kontext chování objektu má záviset na jeho stavu, který se typicky mění za běhu Neflexibilní řešení metody obsahují.
State
State – kontext a problém
Kontext
chování objektu má záviset na jeho stavu, který se typicky mění za běhu
Neflexibilní řešení
metody obsahují větvení v závislosti na stavových proměnných
často výčtové proměnné, konstanty
if / else / switch
Problémy
přidání stavu
vyžaduje upravit všechny metody
void Client::sendMessage(Message & msg) {
switch(_state) {
case DISCONNECTED:
_startConnection();
_send(msg);
break;
case CONNECTED:
_send(msg);
break;
opakující se kód
kontroly stavu
...
}
}
State - řešení
Řešení
objekt „mění svou třídu“
realizováno pomocí dědičnosti
pro každý stav existuje samostatná implementace objektu
se společným rozhraním
State –TCPConnection – motivační příklad
vnější rozhraní pro klienty
abstraktní předek reprezentující stavy
implementace chování v
konkrétních stavech
State – struktura
Struktura
Účastníci
Context (TCPConnection)
State (TCPState)
definuje rozhraní – primární pro uživatele
odkazuje na podtřídy ConcreteState – určuje současný stav
definuje rozhraní objektů reprezentujících jednotlivé stavy Contextu
ConcreteStateA, B, ... (TCPEstablished, TCPListen, TCPClosed)
implementuje konkrétní chování v daném stavu
State – důsledky
Použití
Context deleguje požadavky na instanci stavu ConcreteState
Context může předávat referenci na sebe sama při volání metod stavu
stavy mohou přistupovat přímo ke kontextu
Chování konkrétního stavu je separováno v jednom objektu
nové stavy se jednoduše přidávají definováním potomka State
může vznikat spousta stavů lišících se v drobnostech
Explicitní změna stavu
stavy kontextu nemusí být na první pohled zřejmé
vytváření samostatných objektů pro různé stavy
např. kombinace hodnot proměnných kontextu
přechod na jiný stav je atomický (z pohledu Contextu)
Sdílení objektů State
stavy nemají vlastní proměnné, reprezentovaný stav je určen jejich typem
Flyweight
State – změna stavu 1/2
Kdo bude stav měnit?
State pattern to neříká
Context
Context musí znát pravidla a logiku změn
pro statická kritéria změn vhodné řešení
ConcreteState
flexibilnější – decentralizace logiky
stačí přidat novou třídu a navázat ji na „sousední stavy”
vznik závislostí – stavy o sobě musejí vědět
Context musí obsahovat rozhraní pro změnu stavu
stav musí umět provést
změnu v Contextu
State – změna stavu 2/2
Tabulkou řízený přístup
(Vstup, Stav) → (Funkce, Stav)
Výhody
změna logiky nevyžaduje změnu v kódu, ale jen dat tabulky
pravidelnost
Nevýhody
obvykle pomalejší
table look-up
vs.
volání (virtuální metody)
je složité na automatizované přechody navázat další akce
přechodovým kritériím je z tabulky těžší zpětně porozumět
definice přechodů velmi striktní (výjimky je těžké zakomponovat)
State – konkrétní implementace
Context – TCPConnection
veřejné rozhraní pro klienty
protected změna stavu, přátelská třída TCPState (aby stav mohl provést změnu)
class TCPConnection {
public:
TCPConnection();
TCPConnection(TCPState*);
void Open();
void Close();
void Send();
void Acknowledge();
...
protected:
friend class TCPState;
void ChangeState(TCPState*);
private:
TCPState* _state;
};
počáteční stav
interface pro
změnu stavu
instance stavu
TCPConnection::TCPConnection() { _state = TCPClosed::Instance(); }
TCPConnection::TCPConnection(TCPState* s) {_state = s; }
void TCPConnection::ChangeState(TCPState* s) {_state = s; }
void TCPConnection::Open() {_state->Open(this); }
delegace
State – konkrétní implementace
statická metoda
Instance - Singleton
TCPState
abstraktní třída
interface pro chování
TCPClosed
konkrétní stav
class TCPClosed : public TCPState {
public:
static TCPState* Instance();
virtual void Open(TCPConnection*);
...
};
void TCPClosed::Open (TCPConnection* t) {
// send SYN, receive SYN, ACK, etc.
ChangeState(t, TCPEstablished::Instance());
}
změna stavu
class TCPState {
public:
virtual void Transmit(TCPConnection*, TCPOctetStream*);
virtual void Open(TCPConnection*);
virtual void Close(TCPConnection*);
virtual void Acknowledge(TCPConnection*);
virtual void Send(TCPConnection*);
protected:
void ChangeState(TCPConnection* t, TCPState* s) {
t->ChangeState(s);
};
};
jednotlivé
operace
společná metoda
pro změnu stavu
State – související NV
Singleton
State objekty často singletony
Flyweight
State objekty obsahují pouze chování pro svůj typ, žádný vnitřní stav
sdílení State objektů
Interpreter
může využívat State k definování parse pravidel
Strategy
velmi podobný vzor
implementace State vzoru je postavena na Strategy
liší se v záměru: State objekty lze chápat jako strategie
Bridge
stejná struktura (až na možnost hiearchizace implementorů)
liší se v řešeném problému
State umožňuje změnu v chování objektu
Bridge odstiňuje abstrakci od implementaci
State – souhrn, použití
Souhrn
chování objektu se mění v závislosti na stavu
lokalizace dat a souvisejícího chování v oddělené třídě
odstínění přechodů mezi stavy (konzistence / “atomicita”)
náhrada explicitního větvení virtuálními metodami
vzor neříká, kde bude logika změn stavů
Použití
protokoly, konečné automaty
reakce na události podle stavu
grafické a jiné editory
hry