|
|
|
# Cvičenie 3
|
|
|
|
|
|
|
|
Dneska si ukážeme jednu veľmi výhodnú vlastnosť OOP: observer pattern. Jedná sa o prvý z návrhových vzorov, ktoré budeme preberať.
|
|
|
|
|
|
|
|
Keď ste chceli v C sledovať zmenu nejakej hodnoty, museli ste sa stále dopytovať na zmenu (a keď ste ju sledovali z viacerých miest, tieto dopyty zbytočne stáli výpočtový výkon). Čo keby sme sa na to pozreli z druhej strany: chcem vedieť o zmene nejakej hodnoty, tak sa prihlásim na "odber noviniek" a keď k nejakej zmene dojde, budem o tom oboznámený.
|
|
|
|
|
|
|
|
## 3.1 Let there be light
|
|
|
|
|
|
|
|
Vytvorte si triedu `Crystal` - táto bude reprezentovať svietiaci kryštál (a rozširuje `AbstractActor`). V konštruktore si pripravte 2 animácie: `crystal_on.png`, `crystal_off.png`
|
|
|
|
|
|
|
|
Pridajte metódu `Toggle()` a implementujte ju nasledovne:
|
|
|
|
|
|
|
|
- nech sa pri jej zavolaní zmení stav kryštálu medzi zapnutým a vypnutým
|
|
|
|
- pri zmene stavu zmeňte animáciu
|
|
|
|
|
|
|
|
-----
|
|
|
|
|
|
|
|
Vytvorte si triedu PowerSource - táto bude predstavovať zdroj energie (znovu rozširuje `AbstractActor`).
|
|
|
|
|
|
|
|
Obdobne pridajte dve animácie `source_on.png` a `source_off.png`
|
|
|
|
|
|
|
|
Znovu pridajte metódu `Toggle()` s prakticky rovnakou implementáciou ako v prípade `Crystal`
|
|
|
|
|
|
|
|
Už tu môžete vidieť že máme dve (zatiaľ) prakticky rovnaké triedy, ktoré sa líšia iba v názve a animáciách - princíp DRY (don't repeat yourself) nám hovorí, že by sme tieto veci mali dať dokopy - C# však neumožňuje dediť z viacerých tried súčasne (aj keď nové verzie C# prišli s tzv. default interface methods - interface môže za určitých podmienok implementovať nejakú funkcionalitu), tak to zatiaľ necháme napokoji.
|
|
|
|
|
|
|
|
Vytvorte si však rozhranie
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
public interface ISwitchable
|
|
|
|
{
|
|
|
|
void Toggle();
|
|
|
|
void TurnOn();
|
|
|
|
void TurnOff();
|
|
|
|
bool IsOn();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Nech obidve triedy implementujú toto rozhranie, syntax je nasledovná:
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
public Crystal : AbstractActor, ISwitchable
|
|
|
|
{
|
|
|
|
//magic happens here
|
|
|
|
```
|
|
|
|
|
|
|
|
## 3.2 I see you
|
|
|
|
|
|
|
|
Na samotný observer pattern budeme potrebovať niekoľko rozhraní:
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
public interface IObserver
|
|
|
|
{
|
|
|
|
void Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface IObservable
|
|
|
|
{
|
|
|
|
void Subscribe(IObserver observer);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Nech:
|
|
|
|
- `Crystal` implementuje `IObserver`
|
|
|
|
- `PowerSource` implementuje `IObservable`
|
|
|
|
- V `PowerSource` si držte referenciu na `Crystal` - keď sa zmení stav `PowerSource` dajte o tom kryštálu vedieť
|
|
|
|
|
|
|
|
## 3.3 My command is your wish
|
|
|
|
|
|
|
|
Písať kód, ale nič nevidieť nie je veľmi praktické - takže kus predbehneme cvičenia, o vstupoch z klávesnice a Singleton vzore sa budeme baviť nabudúce. Na zatiaľ si skopírujte do `PowerSource.Update()` nasledujúcu podmienku:
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
if (Input.GetInstance().IsKeyPressed(Input.Key.E))
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
ak táto podmienka bude platiť, zavolajte `Toggle`
|
|
|
|
|
|
|
|
## 3.4 Power! Unlimited Power!
|
|
|
|
|
|
|
|
Momentálne dokážeme napájať jeden kryštál, čo je síce super, ale pravdepodobne až taký odber nemá, že by sme nevedeli pripojiť aj druhý. V C ste používali polia (array), má ich aj C# ale oveľa praktickejšie je použiť nejakú triedu, ktorá nám už funkcionalitu polí zaobaľuje. C# má takýchto tried celú sadu a sú implementované v `System.Collections` namespace. Dneska budeme používať `List<T>`.
|
|
|
|
Kde `T` predstavuje tzv. typový parameter - používa sa, keď vopred nevieme, akého typu bude parameter na vstupe, ale už potrebujeme implementovať funkcionalitu.
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
List<int> list; //list of integer values
|
|
|
|
List<Crystal> crystals; //list of objects of type Crystal
|
|
|
|
...
|
|
|
|
List<string> listOfStrings = new List<string>(); //create a new instance
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
- Pridajte do `IObservable` metódu `void Unsubscribe(IObserver observer)`
|
|
|
|
- Upravte `PowerSource` tak, aby bolo možné pridávať a odoberať Observerov
|
|
|
|
- na pridanie použite `List.Add(T value)`
|
|
|
|
- na odobratie môžete použiť `List.Remove(T value)` - pravdepodobne budete musieť skontrolovať, či daný prvok už v zozname je - ako na to, pozrite si dostupné metódy pomocou dopĺňania kódu (ctrl+spacebar)
|
|
|
|
- V rámci `TurnOn() / TurnOff()` upozornite všetky kryštály o zmene stavu zdroja elektriky
|
|
|
|
|
|
|
|
Syntax pre `foreach` cyklus je:
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
foreach (string s in listOfStrings)
|
|
|
|
{
|
|
|
|
Console.WriteLine(s);
|
|
|
|
} |
|
|
|
\ No newline at end of file |