Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

4. díl - Upomínač narozenin - Logická vrstva

C# .NET Formuláře Windows Forms Upomínač narozenin - Logická vrstva

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

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. Jméno 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:

  1. Získáme si aktuální datum (bez času) pomocí DateTime.Today.
  2. 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.
  3. 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.
  4. 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:

  1. Získáme si aktuální datum (bez času).
  2. Získáme datum dalších narozenin přičtením věku + 1 k datu narození.
  3. Data odečteme a celkový rozdíl ve dnech vrátíme. Jelikož je rozdíl typu double, musíme ho zkonvertovat na int.
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 seriálu 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 kontrolky 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 kontrolek 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 editace osob, musela by třída Osoba implementovat rozhraní INotifyProper­tyChanged. Jakákoli změna (např. jména) by se poté automaticky projevila ve všech kontrolká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 nejblížší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 BindingListu. 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 Práce se 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 BindingListu. 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 u LINQu 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.


 

Stáhnout

Staženo 832x (342.7 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
3 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (2)

 

 

Komentáře
Zobrazit starší komentáře (35)

Avatar
Napal
Člen
Avatar
Napal:16.12.2015 21:03

Můj komentář byl asi trochu zapomenut, dokázal by mi někdo odpovědět? :) děkuji

 
Odpovědět 16.12.2015 21:03
Avatar
Odpovídá na Napal
Michal Štěpánek:16.12.2015 21:50

V podstatě by to šlo i bez této proměnné, ale hned v dalším řádku je použita pro výpočet věku...

public int SpoctiVek()
{
        DateTime dnes = DateTime.Today;
        int vek = dnes.Year - Narozeniny.Year;
        if (dnes < Narozeniny.AddYears(vek))
                vek--;
        return vek;
}
Odpovědět 16.12.2015 21:50
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Napal
Člen
Avatar
Odpovídá na Michal Štěpánek
Napal:17.12.2015 20:17

Tam ano, tam to chápu, ale já se ptal na metodu ZbyvaDni(), kde je taky vytvořená, ale není nijak využitá. (podle mě)

public int ZbyvaDni()
{
        DateTime dnes = DateTime.Today;
        DateTime dalsiNarozeniny = Narozeniny.AddYears(SpoctiVek() + 1);

        TimeSpan rozdil = dalsiNarozeniny - DateTime.Today;

        return Convert.ToInt32(rozdil.TotalDays);
 
Odpovědět 17.12.2015 20:17
Avatar
Odpovídá na Napal
Michal Štěpánek:18.12.2015 9:05

Ano, tam se vytváří zbytečné. Myslím si, že to chtěl David udělat přehledné a pak zapomněl tu proměnnou použít.

Odpovědět  +2 18.12.2015 9:05
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Peter Kováčik:20.11.2016 11:06

Môže niekto poslať celý kód programu?

 
Odpovědět 20.11.2016 11:06
Avatar
Odpovídá na Peter Kováčik
Michal Haňáček:20.11.2016 11:27

Vždyť jsou zdrojáky ke stažení ...

Odpovědět 20.11.2016 11:27
Každé rozhodnutí a každý krok v životě nás někam posune. Bohužel jen některé nás posouvají dopředu.
Avatar
Martin Samiec:6. července 15:21

Ahojky všem. Mám Microsoft Visual 2015. a jeden kód který je tady uveden už nejde v 2015ce implikovat. A to konkrétně metoda NajdiNejblizsi(). Předkládám upravenou verzi:

public Osoba NajdiNejblizsi()
{
var serazeneOsoby = (from o in Osoby
orderby o.ZbyvaDni()
select o).First();
return serazeneOsoby;
}

Ať se daří... :-)

 
Odpovědět 6. července 15:21
Avatar
Odpovídá na Martin Samiec
Michal Štěpánek:6. července 16:26

A proč by neměl jít ve VS2015? Jestli ti nešel, tak sis tam něco špatně napsal. Mě šel normálně...

Odpovědět 6. července 16:26
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
František Hejský:27. srpna 22:02

Jak mám vytvořit tu třídu? Nemůžu to nikde najít :(

 
Odpovědět 27. srpna 22:02
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 45. Zobrazit vše