• Nem Talált Eredményt

Állapot – State

In document Programozás technika (Pldal 113-118)

4. Programozási technológiák – Tervezési minták

4.4. Viselkedési tervezési minták

4.4.1. Állapot – State

}

4.3.3.4. Gyakorló feladat

Az alábbi leírás szerint készítsünk forráskódot. A megoldáshoz használjuk a helyettes tervezési mintát!

Feladat

A fenti forráskódot úgy írjuk át, hogy minden részeredmény bekerüljünk az átmeneti tárba (cache). A rekurzió során is figyeljük, hogy a kívánt részeredmény megvan-e az átmeneti tárban. Csináljuk ide futás idő összehasonlítást az egyes megoldások között.

Feladat

Ki ne ismerné azokat a helyes kis automatákat, amik némi pénz bedobása után jópofa dolgokat adnak egy műanyag golyóban. A hálózat üzemeltetője jelentkezett cégünknél, hogy szeretné az interneten keresztül felügyelni a gépek állapotát, mint például tudni, hogy mennyi golyó van még benne. A megvalósítási megbeszélésen egyik kollegánk felhozta, hogy Ő volt egy csapatépítő tréningen ahol az esti tábortűznél egy nagyszakállú, bölcs és kellőképpen öreg programozó mesélt nekik a proxyról és hogy az pont valami ilyesmire való. Szakkönyvek, internet és valóban az öregnek igaza volt. Innen már könnyű út vezetett a megvalósításig.

Természetesen az absztrakt osztályok kidolgozásával kezdtük, először is a közös felületet kellett megírni, amin a helyettes és a mi kis automatánk megtalálja a közös nyelvet. Tehát ebbe az osztályba került a MennyiGolyo() és a MennyiPenz() abstract függvények. A szakirodalomból azt is megtudtuk, hogy a visszatérési értékeknek seriaziable-nek kell lennie a hálózati forgalom miatt. Ezután a Proxy-t implementáltuk, feladata, hogy a kliens kérését (a főnők utasítását) eljutassa az automatának. Ami ténylegesen átmegy az a meghívott függvény neve és az esetleges argumentumai. Az igazi kemény munkát ezután az automata (ValódiTárgy) végzi, hiszen csak ő tudja hány golyó rejt még meglepetést az arra sétálóknak. Meghívja a MennyiGolyo() függvényt, majd a kapott eredmény visszajutatja a Proxy-nak, mely büszkén mutatja azt fel a kliensnek. Persze ebben az esetben nem szabad megfeledkezni a kivételek kezeléséről, mert ami a hálózaton indul az nem biztos, hogy oda is ér.

4.4. Viselkedési tervezési minták

A viselkedési tervezési minták középpontjában az algoritmusok és az objektumokhoz rendelt felelősségi körök állnak. E minták az osztályok és objektumok rendszerén túl a közöttük folyó kommunikációt és a felelősségi köröket is leírják. A viselkedési minták öröklés helyett összetételt alkalmaznak.

4.4.1. Állapot – State

Célja: Lehetővé teszi egy objektum viselkedésének megváltozását, amikor megváltozik az állapota. Példa:

TCPConnection osztály egy hálózati kapcsolatot reprezentál; Három állapota lehet: Listening, Established, Closed; a kéréseket az állapotától függően kezeli.

Használjuk, ha

1. az objektum viselkedése függ az állapotától, és a viselkedését az aktuális állapotnak megfelelően futás közben meg kell változtatnia, illetve

2. a műveleteknek nagy feltételes ágai vannak, melyek az objektum állapotától függenek.

Előnyök:

1. Egységbe zárja az állapotfüggő viselkedést, így könnyű új állapotok bevezetése.

2. Áttekinthetőbb kód (nincs nagy switch-case szerkezet).

3. A State objektumokat meg lehet osztani.

Hátrányok: Nő az osztályok száma (csak indokolt esetben használjuk).

4.4.1.1. Példa

Az Állapotgép tervezési mintát a következő példán keresztül mutatjuk be: Feladatunk, hogy elkészítsünk egy rendkívül egyszerű audio lejátszót. A lejátszónknak a következőképpen kell működnie. Ha a lejátszó készenléti állapotban van, akkor a lejátszás gomb hatástalan, az audio forrás gombbal pedig megkezdődik az mp3 fájl lejátszása. Mp3 lejátszás közben a lejátszás gomb leállítja a lejátszást, az audio forrás gomb pedig rádióhallgatást tesz lehetővé. Ha az mp3 lejátszás szünetel, akkor a lejátszás gomb hatására folytatódik a lejátszás, az audio forrás gomb pedig ebben az esetben is rádióhallgatást tesz lehetővé. Rádióhallgatás közben a lejátszás gomb adót vált, az audio forrás gomb pedig készenléti üzemmódot eredményez. A leírt összetett működés eléréséhez az állapotgépet valósítjuk meg. Létrehozzuk az audio lejátszó osztályunkat, amelynek van egy belső állapota, valamint egy lejátszás és egy audio forrás metódusa. Létrehozunk egy alap állapot osztályt is, melyből a később szükséges állapotaink származni fognak, és amelyeke később a lejátszónk állapotai lehetnek.

Az, hogy a lejátszónk az egyes állapotokban, hogyan reagál a lejátszás és audio forrás lenyomására, az egyes állapotoktól függ, ezért ezek az egyes állapotokban vannak definiálva, csak úgy, mint az állapotátmenetek is.

Módszerünk előnye, hogy könnyedén bővíthetjük a lejátszónkat újabb állapotokkal, és ezáltal újabb funkciókkal bővülhet.

4.4.1.2. Forráskód using System;

namespace ÁllapotGép {

/// <summary>

/// State/Állapotgép viselkedési minta /// média lejátszó

/// két gomb /// 4 állapot

/// a két gomb viselkedése más és más lesz a 4 belső állapottól függően /// lesz egy: Állapot

/// Play gomb /// Audió forrás gomb /// Állapotváltozások:

/// Állapotok: készenlét, mp3 lejátszás, mp3 megállítás, rádió hallgatás /// Lejátszás: stop-paused, start-play, next station

/// Audió forr: mp3 play, rádió play, rádió play, készenlét /// </summary>

public class AudioPlayer {

private AudioPlayerState _state; // ebben tároljuk a belső állapotot public AudioPlayer(AudioPlayerState state) { _state = state; } public AudioPlayerState SetState

{

get { return _state; } set { _state = value; } }

public void PressPlay() { _state.PressPlay(this); }

public void PressAudioSource() { _state.PressAudioSource(this); } }

public abstract class AudioPlayerState // állapot reprezentálása {

// a két gomblenyomása

public abstract void PressPlay(AudioPlayer player);

public abstract void PressAudioSource(AudioPlayer player);

}

public class StandbyState : AudioPlayerState // készenléti állapot {

public StandbyState() { Console.WriteLine("StandBy"); } public override void PressPlay(AudioPlayer player) {

Console.WriteLine("Play pressed: no effect");

}

public override void PressAudioSource(AudioPlayer player) {

player.SetState = new MP3PlayingState();

} }

public class MP3PlayingState : AudioPlayerState // mp3 hallgatás állapot {

public MP3PlayingState() { Console.WriteLine("Playing MP3"); } public override void PressPlay(AudioPlayer player)

{

player.SetState = new MP3PausedState();

}

public override void PressAudioSource(AudioPlayer player)

{

player.SetState = new RadioState();

} }

public class MP3PausedState : AudioPlayerState // a megállított mp3 állapot {

public MP3PausedState() { Console.WriteLine("Paused MP3"); } public override void PressPlay(AudioPlayer player)

{

player.SetState = new MP3PlayingState();

}

public override void PressAudioSource(AudioPlayer player) {

player.SetState = new RadioState();

} }

public class RadioState : AudioPlayerState // a rádió állapot {

public RadioState() { Console.WriteLine("Playing Radio"); } public override void PressPlay(AudioPlayer player)

{

Console.WriteLine("Switch to next Station");

}

public override void PressAudioSource(AudioPlayer player) {

player.SetState = new StandbyState();

} }

class Program {

static void Main(string[] args) {

AudioPlayer player = new AudioPlayer(new StandbyState());

player.PressPlay();

player.PressAudioSource();

player.PressPlay();

player.PressPlay();

player.PressAudioSource();

player.PressPlay();

player.PressAudioSource();

Console.ReadLine();

} } }

4.4.1.3. UML-ábra

22. ábra

4.4.1.4. Gyakorló feladat

Az alábbi leírás szerint készítsünk forráskódot. A megoldáshoz használjuk az állapot tervezési mintát!

Feladat

Egy napon az egyik munkatársunk kiment a kávéautomatához egy frissítő italért, pár perc múlva vörös fejjel és kezében az automata programjával jött vissza. Kérdésünkre elmondta, hogy nem először jár úgy, hogy a gép elnyeli az aprót, de kávét nem add, úgyhogy gondolta, a programmal lesz a baj. Elkezdtük tanulmányozni a szoftvert, mely tele volt csúnya és néhol egymásba ágyazott IF feltételekkel (ezek váltották a belső állapotot, ha bedobtuk a pénzt vagy elfogyott a kávépor, stb.). Rögtön gondoltuk, hogy erre van jobb módszer. Először hívtunk egy grafikust, aki lerajzolt minket, majd egy állapotdiagramban a gép lehetséges belső állapotait (pl.

nincs apró, apró bedobva stb.). Ebből rögtön láttuk, hogy egyes állapotokban a gépnek meg kell, hogy változzon a viselkedése (ha nincs apró és megnyomom a kávé gombot nem adhat kávét, míg ha van apró, akkor illik legalább valami sötét löttyöt adni). Így már tudtunk csinálni egy interfészt az állapotoknak. Ebből az osztályból dolgoztuk ki a konkrét állapotokat külön osztályokba. Alapesetben a gép „a nincs apró” állapotban (osztályban)

van, de ha dobunk be aprót lecseréli az állapotát (osztályát) „apró bedobva” típusúra. Mióta megírtuk a programot nekünk már apró sem kell a kávéhoz.

In document Programozás technika (Pldal 113-118)