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
