Geek tričko zdarma Geek tričko zdarma
Tričko zdarma! Stačí před dobitím bodů použít kód TRIKO15. Více informací zde

Lekce 4 - Upomínač narozenin - Logická vrstva

Unicorn College 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. 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:

  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
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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 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 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 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.


 

Stáhnout

Staženo 993x (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?
5 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 sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
Upomínač narozenin - Návrh formulářů
Všechny články v sekci
Okenní aplikace v C# .NET ve Windows Forms
Miniatura
Následující článek
Upomínač narozenin - Propojení prezentační a logické vrstvy
Aktivity (3)

 

 

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

Avatar
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.7.2017 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.7.2017 15:21
Avatar
Odpovídá na Martin Samiec
Michal Štěpánek:6.7.2017 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.7.2017 16:26
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
František Hejský:27.8.2017 22:02

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

 
Odpovědět 27.8.2017 22:02
Avatar
Robert Landa
Člen
Avatar
Robert Landa:25.1.2018 17:04

Ještě bych dodal, že je potřeba použít knihovnu "using System.Componen­tModel" pro BindingList, ale kdo hledá a není pouhý opisovač vždy najde :)

 
Odpovědět 25.1.2018 17:04
Avatar
Alvaro Luis
Člen
Avatar
Alvaro Luis:29.11.2018 21:09

Tohle je kód formuláře OsobaForm, že?

 
Odpovědět 29.11.2018 21:09
Avatar
Odpovídá na Alvaro Luis
Andy Scheuchzer:29.11.2018 21:57

Nevidím tam ani jeden kousek kódu, který by se měl dávat do formuláře.

V naší aplikaci budou zcela jistě figurovat osoby, vytvořme jim tedy třídu.

Přidejte si k projektu tedy třídu SpravceOsob a učiňte ji veřejnou.

Odpovědět 29.11.2018 21:57
Člověk, co si myslí, že snědl všechnu moudrost světa, i když tomu tak není.
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 48. Zobrazit vše