Lekce 4 - Upomínač narozenin - Logická vrstva
V minulé lekci, Upomínač narozenin - Návrh formulářů, jsme navrhli kompletně formuláře pro naši aplikaci.
V tomto tutoriálu se budeme zabývat návrhem logické vrstvy, tedy tříd, které obsahují logiku aplikace.
Osoba
V naší aplikaci budou zcela jistě figurovat osoby, vytvořme jim tedy
třídu. Před třídu nezapomeňte dát modifikátor public
.
Vlastnosti
Osoba bude mít 2 vlastnosti: jméno a narozeniny. Jmeno
bude
string
, Narozeniny
budou typu DateTime
.
Tyto vlastnosti nastavíme pomocí parametrického konstruktoru.
public class Osoba { public string Jmeno { get; set; } public DateTime Narozeniny { get; set; } public Osoba(string jmeno, DateTime narozeniny) { Jmeno = jmeno; Narozeniny = narozeniny; } }
Metody
Kromě konstruktoru bude třída disponovat metodami SpoctiVek()
a ZbyvaDni()
.
SpoctiVek
Metoda vypočítá a vrátí aktuální věk osoby v celých letech.
Výpočet bohužel není jen o tom odečíst dva datumy, jelikož
TimeSpan
neumí zjistit počet let, pouze počet dní. Výpočet
věku tedy provedeme následujícím způsobem:
- Získáme si aktuální datum (bez času) pomocí
DateTime.Today
. - Věk spočítáme jako rozdíl roků v aktuálním datu a datu narozenin. Asi je vám jasné, že tento věk není přesný. Pokud jsme se narodili 1.2.1990 a je 1.1.2010, není nám 20 let, ale jen 19. Z toho důvodu provedeme korekci.
- V případě, že je aktuální datum menší (dříve) než datum narození po přidání námi vypočítaných let, nastal výše uvedený případ a my věk o rok snížíme.
- Hotový věk vrátíme.
Kód metody bude následující.
public int SpoctiVek() { DateTime dnes = DateTime.Today; int vek = dnes.Year - Narozeniny.Year; if (dnes < Narozeniny.AddYears(vek)) vek--; return vek; }
ZbyvaDni
Metoda nám vrátí kolik dní zbývá do narozenin osoby. To zjistíme následujícím způsobem:
- Získáme si aktuální datum (bez času).
- Získáme datum dalších narozenin přičtením věku + 1 k datu narození.
- Data odečteme a celkový rozdíl ve dnech vrátíme. Jelikož je rozdíl
typu
double
, musíme ho zkonvertovat naint
.
public int ZbyvaDni() { DateTime dnes = DateTime.Today; DateTime dalsiNarozeniny = Narozeniny.AddYears(SpoctiVek() + 1); TimeSpan rozdil = dalsiNarozeniny - DateTime.Today; return Convert.ToInt32(rozdil.TotalDays); }
ToString
Jelikož budeme osoby vypisovat, přepíšeme metodu ToString()
tak, aby vracela jméno osoby:
public override string ToString() { return Jmeno; }
Správce osob
Další logickou komponentou aplikace bude správce osob. Třída se bude starat o osoby, bude je umět přidávat, odebírat a jejich seznam ukládat do souboru a opětovně načíst. Konečně bude umět mezi osobami vyhledat tu, která má nejbližší narozeniny.
Přidejte si k projektu tedy třídu SpravceOsob
a učiňte ji
veřejnou.
Vlastnosti a atributy
Jedinou veřejnou vlastností třídy je seznam osob. Seznam je typu
BindingList
. S touto kolekcí jsme se v kurzu ještě nesetkali.
Jedná se o chytřejší List
, který na sobě umí vyvolat
událost změny v případě, že se změní jeho obsah. Díky tomuto mechanismu
se automaticky obnoví všechny prvky na formuláři, které mají nastavený
jako zdroj dat právě tento BindingList
. Asi si dokážete
představit, že obnovovat ručně desítky prvků na formuláři v případě
změny může být velice nepřehledné. Jakmile v naší aplikaci přidáme
novou osobu, bude ihned vidět v seznamu osob aniž bychom ho obnovovali,
obnoví se sám. BindingList
inicializujeme v konstruktoru.
Pokud bychom chtěli implementovat i editaci osob, musela by třída
Osoba
implementovat rozhraní INotifyPropertyChanged
.
Jakákoli změna (např. jména) by se poté automaticky projevila ve všech
prvcích všech formulářů, kde osoba figuruje. Tímto se však pro
zjednodušení zabývat nebudeme.
Třída zatím vypadá takto:
public class SpravceOsob { public BindingList<Osoba> Osoby { get; set; } public SpravceOsob() { Osoby = new BindingList<Osoba>(); } }
Metody
Kromě přidávání a odebírání bude třída umět i nalézt osobu s nejbližšími narozeninami. Ukládání a načítání osob do/ze souboru necháme na později.
Pridej()
Metoda přidá novou osobu do BindingList
u. Jelikož osobu
přidáváme formulářem, hodí se nám, aby metoda brala v parametrech
vlastnosti osoby a na jejich základě vytvořila novou instanci. Z data
narození uložíme pouze část s datem, tedy bez času.
Před přidáním zkontrolujeme, zda jméno není příliš krátké nebo není zadané datum v budoucnosti. Pokud nějaká z těchto situací nastane, vyhodíme výjimku. Právě výjimky jsou správným způsobem, jak s chybami v objektových aplikacích pracovat.
Výjimky jsou detailněji popsané v sekci Soubory v C# .NET. Pokud jste se s nimi ještě
nesetkali, bude vám stačit vědět, že výjimka se vyvolá pomocí
klíčového slova throw
, za kterým následuje instance výjimky.
Výjimek máme několik typů včetně možnosti vytvořit si vlastní. V našem
případě se nám hodí ArgumentException
(chyba v argumentu). Do
konstruktoru výjimky zadáváme text chyby. Jakmile je výjimka vyvolána,
metoda již dále nepokračuje. Jak na chybu reagovat si ukážeme až budeme
metodu volat z formuláře.
public void Pridej(string jmeno, DateTime datumNarozeni) { if (jmeno.Length < 3) throw new ArgumentException("Jméno je příliš krátké"); if (datumNarozeni.Date > DateTime.Today) throw new ArgumentException("Datum narození nesmí být v budoucnosti"); Osoba osoba = new Osoba(jmeno, datumNarozeni.Date); Osoby.Add(osoba); }
Odeber
Metoda odebere osobu z BindingList
u. Protože vždy budeme
chtít odebírat již hotovou osobu, bere metoda v parametru právě tu.
public void Odeber(Osoba osoba) { Osoby.Remove(osoba); }
NajdiNejblizsi
Metoda najde a vrátí osobu, která má nejbližší narozeniny. K
vyhledání osoby v listu použijeme LINQ
metodu OrderBy()
, která osoby uspořádá podle toho, kolik dní
zbývá do jejich narozenin. Výsledek uložíme do kolekce, jejíž typ
neuvedeme a použijeme místo toho klíčové slovo var
, jak je v
LINQ zvykem. Následně vrátíme první osobu. Metodu bychom měli volat jen
tehdy, když jsou v listu nějaké osoby. Ačkoli by z kódu mělo být jasné,
co metoda dělá, můžete se samozřejmě podívat na tutoriály v sekci Kolekce a LINQ v C# .NET, kde je technologie
LINQ detailně popsána.
public Osoba NajdiNejblizsi() { var serazeneOsoby = Osoby.OrderBy(o => o.ZbyvaDni()); return serazeneOsoby.First(); }
Pokračovat budeme v příští lekci, Upomínač narozenin - Propojení prezentační a logické vrstvy, kdy aplikaci zprovozníme. Dosavadní zdrojový kód je ke stažení níže.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 1156x (342.7 kB)
Aplikace je včetně zdrojových kódů v jazyce C#