Nokia 630 ZDARMA pro nové majitele MSDN

Aplikace pro více zařízení (4.) – Abstrakce platformy

  • Comments 4

Vítejte v miniseriálu, který vám má pomoci psát kód tak, aby byl, aby byl co nejvíce znovupoužitelný v různých typech aplikací. V prvním díle jsme se zabývali potřebným nástrojem, což jsou zejména portable libraries. Ve druhém díle jsme se věnovali základnímu návrhovému vzoru – MVVM, zejména prostřední vrstvě ViewModel, ve třetím díle potom XAMLu používanému pro View. Dnes se budeme věnovat abstrakci platformy.

V čem je vlastně problém?

Při vývoji typické aplikace určitě narazíte na potřebu používat řadu systémových služeb jako např. kryptografii, síťovou komunikaci, uložení nastavení, notifikaci, autentizaci, ...

Tyto služby typicky potřebuje vrstva ViewModel anebo Model využívat, ale není možné je implementovat jako portable library (PL), neboť jsou implementovány na každé platformě různě – používají různé mechanismy, třídy, knihovny, … Navíc jsou implementovány v platformově závislých knihovnách, takže není možné je z PL referencovat.

Řešení = abstrakce platformy

Vyřešení tohoto problému není příliš obtížné – skládá se z následujících kroků.

  • Ve sdíleném kódu (PL) se definují rozhraní/abstraktní třídy pro jednotlivé systémové služby
  • Kód v PL (ViewModel, Model) znají a využívají pouze tato definovaná rozhraní, nikoliv konkrétní implementace.
  • Každá platforma definuje svoje konkrétní implementace těchto rozhraní/abstraktních tříd.
  • Při startu aplikace na dané platformě jsou konkrétní implementace zpřístupněny sdílenému kódu, který je pak volá.

Zpřístupnění zmíněné v posledním kroku může mít různou podobu. Například lze ve sdíleném kódu vytvořit statickou třídu Services, která má jako vlastnosti příslušné služby (např. vlastnost Storage typu IStorageService). Ve sdíleném kódu pak můžete používat tuto funkci pomocí Services.Storage, při startu každé platformy samozřejmě musíte přiřadit vlasnosti Services.Storage její konkrétní implementaci.

Inversion of Control

Populární technikou pro vytváření dobře testovatelných  aplikací s kontrolovanými závislostmi mezi komponentami je návrhový vzor Inversion of Control (IoC). Ten je často používán v kombinaci se vzorem Service Locator.

Oba tyto vzory jsou velmi jednoduchým způsobem implementovány i v knihovně MVVMLight, proč je tedy nevyužít pro zjednodušení a zefektivnění kódu. Implementace je založena na třídě ServiceLocator z Microsoft patterns & practices. Používá jednoduchý IoC kontejner jménem SimpleIoC, jehož hlavní devizou je – jak vyplývá i z názvu – jednoduchost.

Např. potřebujeme vytvořit službu pro abstrakci navigace mezi jednotlivými obrazkovkami, která je na každé platformě různá. Za tímto účelem definujeme v portable library (sdíleném kódu) rozhraní INavigationService:

public interface INavigationService
{
    void Navigate(string type, object parameter = null);
}

Tuto třídu pak implementujeme pro každou konkrétní platformu. Např. pro Windows Store může být implementace následující:

class NavigationService : INavigationService
{
    private PhoneApplicationFrame _rootFrame;
    public NavigationService(PhoneApplicationFrame rootFrame)
    {
        _rootFrame = rootFrame;
    }
   
    public void Navigate(string type, object parameter = null)
    {
        switch (type)
        {
            case "MainPage":
                _rootFrame.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
                break;
        }
    }
}

Při startu aplikace na dané platformě pak zaregistrujeme tuto konkrétní implementaci rozhraní:

SimpleIoc.Default.Register<INavigationService>(
    () => new NavigationService(Window.Current.Content as Frame));

Ve sdíleném kódu pak implementujeme statickou třídu Services pro snadný přístup k jednotlivým službám:

public static class Services
{
    … kráceno …
    public static INavigationService Navigation
    {
        get { return ServiceLocator.Current.GetInstance<INavigationService>(); }
    }
}

Odměnou za tyto přípravné práce je nám velmi elegantní využívání této služby v kódu:

Services.Navigation.Navigate("MainPage");

Podobným způsobem snadno abstrahujeme i ostatní služby platformy.

Vzorové řešení

Opět jako příklad použiji jednoduchou, ale zcela funkční aplikaci, jejíž kód si dnes konečně můžete stáhnout. Kam umístit platformově závislé funkce by mělo být jasné z obrázku:

image

Veškerá rozhraní jsou implementována ve sdílené knihovně, jejich implementace je pak zvlášť pro každou platformu v platformově závislé knihovně, a to samozřejmě opakovaně (v tomto případě 2x).

Konkrétně během vývoje vyvstala potřeba pro abstrakci následujících funkcí:

  • Lokální úložiště (IStorageService) – je třeba ukládat některé údaje v lokálním úložišti (např. přihlašovací token pro mobilní službu
  • Notifikace (INotificationService) – pomocná služba pro získání informací k registraci notifikace pro zařízení a obsluhu příchozích notifikacích
  • Navigace (INavigationService) – přepínání mezi jednotlivými obrazovkami aplikace
  • Dialogy (IDialogService) – jednoduché dialogy, jako je zobrazení chybového hlášení nebo potvrzení otázky (např. při mazání)
  • Uživatelské rozhraní pro přihlášení do Azure Mobile Service (IMobileServiceUI) – poměrně speciální záležitost pro embedovaný prohlížeč sloužící k autentizaci uživatelů pro službu

Kód ke stažení

Jak jsem již třikrát slíbil, kód této vzorové aplikace je volně k dispozici. Dnes si ho konečně můžete stáhnout zde.

Kód využívá můj Azure Mobile Service. Klidně si jej můžete spustit proti mé službě, něco si do ní uložit a nechat posílat notifikace. Neručím ovšem za to, že služba bude vždy dostupná, že ji do budoucna nezměním tak, že nebude s tímto kódem kompatibilní anebo že nevymažu data v ní uložená.
Pokud byste si chtěli udělat vlastní backend, více informací o službě Azure Mobile Service naleznete např. v tomto miniseriálu.

Závěr a pozvánka

Dne 9.4. od 10:00 hodin pořádáme na výše uvedené téma hodinový online seminář, kde se o problematice můžete dozvědět více. Využijte příležitosti položit konkrétní dotazy, které vás zajímají. Zaregistrovat se můžete zde.

Původně jsem myslel, že seriál tímto dílem ukončím. Při jeho psaní jsem však dostal chuť vylepšit svůj kód ještě o unit testy a vylepšit jeho testovatelnost na hranici možností dnešních nástrojů. Takže se můžete těšit ještě na pátý díl, byť se objeví s časovým odstupem.

Michael

  • Super seriál, který se mi opravdu líbí a hodně mi pomohl. Ještě by mě zajímalo, jak bych měl abstrahovat lokální databázi pro platformy WP7, WP8 a Windows Store aplikace.

  • Abstrakce databaze je mimoradne tezka. Dnes je docela trend delat POCO objekty (tedy objekty nezavisle na databazi), napr. entity framework v .NET frameworku. Ale najit relacni mapovani jako portable library, to bude orisek.

    Asi nejlepsi je udelat si nejaky interface pro repository s metodami typu AddCustomer, ListCustomers, atd. a "vsadit" a pak delat implementaci pro kazdou použitelnou databazi a platformu.

    Najit databazi jako portable library je dle mého soudu dnes nemozne.

  • Děkuji za odpověď. Hledal jsem možné řešení a myslím si, že jedna z možností pro WP/WinRT by mohla být databáze SQLite, ale asi i tak spíše zkusím implementovat řešení pro každou platformu zvlášť.

  • I kdyz pouzijete SQLite, je to jina knihovna pro kazdou platformu, coz je hrozna otrava. Budete tam mit stejny kod vicekrat :-(

    Alespon tedy nevim, ze by meli i formu portable library.

Page 1 of 1 (4 items)
Leave a Comment
  • Please add 1 and 4 and type the answer here:
  • Post