it-swarm-eu.dev

Kdy jít plynule v C #?

V mnoha ohledech se mi opravdu líbí myšlenka rozhraní Fluent, ale se všemi moderními funkcemi C # (inicializátory, lambdy, pojmenované parametry) se mi zdá, že si myslím, „stojí za to?“ A „Je to ten správný vzorec použití?". Mohl by mi někdo dát, ne-li přijatý postup, alespoň svou vlastní zkušenost nebo matici rozhodování, kdy použít plynulý vzorec?

Závěr:

Některá dobrá pravidla z odpovědí doposud:

  • Plynulá rozhraní značně pomáhají, když máte více akcí než nastavovačů, protože volání profitují z předávání kontextu více.
  • Plynulá rozhraní by měla být považována za vrstvu přes vrchol api, ne za jediný prostředek použití.
  • Moderní funkce, jako jsou lambdy, inicializátory a pojmenované parametry, mohou pracovat ruku v ruce, aby plynulejší rozhraní bylo ještě přátelštější.

Zde je příklad toho, co myslím moderními funkcemi, díky nimž se cítím méně potřebnými. Vezměme si například (možná špatný příklad) plynulé rozhraní, které mi umožňuje vytvořit zaměstnance jako:

Employees.CreateNew().WithFirstName("Peter")
                     .WithLastName("Gibbons")
                     .WithManager()
                          .WithFirstName("Bill")
                          .WithLastName("Lumbergh")
                          .WithTitle("Manager")
                          .WithDepartment("Y2K");

Lze snadno napsat pomocí inicializátorů, jako jsou:

Employees.Add(new Employee()
              {
                  FirstName = "Peter",
                  LastName = "Gibbons",
                  Manager = new Employee()
                            {
                                 FirstName = "Bill",
                                 LastName = "Lumbergh",
                                 Title = "Manager",
                                 Department = "Y2K"
                            }
              });

V tomto příkladu bych také mohl použít pojmenované parametry v konstruktérech.

80
Andrew Hanlon

Psaní plynulého rozhraní (s ním jsem dabbled ) vyžaduje více úsilí, ale má to výplaty, protože pokud to uděláte správně, je výsledný uživatelský kód jasnější. Je to v zásadě forma specifického jazykového jazyka.

Jinými slovy, pokud je váš kód načten mnohem více, než je napsán (a jaký kód není?), Měli byste zvážit vytvoření plynulého rozhraní.

Plynulá rozhraní jsou více o kontextu a jsou mnohem víc než jen způsoby konfigurace objektů. Jak vidíte ve výše uvedeném odkazu, k dosažení:

  1. Kontext (takže když obvykle provádíte mnoho akcí ve stejném pořadí, můžete je zřetězit, aniž byste museli znovu a znovu prohlašovat svůj kontext).
  2. Viditelnost (když jdete na objectA. pak vám inteligence dává spoustu rad. V mém případě výše, plm.Led. vám poskytuje všechny možnosti pro ovládání vestavěné LED a plm.Network. vám poskytuje věci, které můžete dělat se síťovým rozhraním. plm.Network.X10. vám dává podmnožinu síťových akcí pro zařízení X10. U inicializátorů konstruktoru to nedostanete (pokud si nepřejete, aby byl objekt konstruován pro každý jiný typ akce, který není idiomatický).
  3. Reflexe (nepoužívá se ve výše uvedeném příkladu) - schopnost převzít výraz LINQ a manipulovat s ním je velmi výkonný nástroj, zejména v některých pomocných API, které jsem vytvořil pro testy jednotek. Dokážu předat výraz getter get, sestavit spoustu užitečných výrazů, zkompilovat a spustit je, nebo dokonce použít getter k nastavení mého kontextu.

Jedna věc, kterou obvykle dělám, je:

test.Property(t => t.SomeProperty)
    .InitializedTo(string.Empty)
    .CantBeNull() // tries to set to null and Asserts ArgumentNullException
    .YaddaYadda();

Nechápu, jak můžete něco takového udělat i bez plynulého rozhraní.

Edit 2 : Můžete také udělat opravdu zajímavá vylepšení čitelnosti, jako například:

test.ListProperty(t => t.MyList)
    .ShouldHave(18).Items()
    .AndThenAfter(t => testAddingItemToList(t))
    .ShouldHave(19).Items();
28
Scott Whitlock

Scott Hanselman o tom mluví v epizoda 260 jeho podcastu Hanselminutes s Jonathanem Carterem. Vysvětlují, že plynulé rozhraní je spíš jako uživatelské rozhraní na rozhraní API. Neměli byste poskytovat plynulé rozhraní jako jediný přístupový bod, ale měli byste jej poskytovat jako nějaký druh uživatelského rozhraní kódu nad „běžným rozhraním API“.

Jonathan Carter také mluví o návrhu API na svém blog .

24
Kristof Claes

Plynulá rozhraní jsou velmi výkonné funkce, které poskytují v kontextu vašeho kódu, pokud nemají správné důvody.

Pokud je vaším cílem jednoduše vytvořit masivní jednořádkové kódové řetězce jako druh pseudo-černé skříňky, pak pravděpodobně vyštěkáváte nesprávný strom. Pokud jej naopak používáte pro zvýšení přidané hodnoty rozhraní API poskytováním prostředků pro řetězové volání metod a zlepšení čitelnosti kódu, pak se spoustou dobrého plánování a úsilí domnívám, že úsilí stojí za to.

Při vytváření plynulých rozhraní bych se vyhnul tomu, co se zdá být běžným "vzorem", kde pojmenováváte všechny své plynulé metody "s" - něčím, protože okrádá potenciálně dobré rozhraní API o svůj kontext, a proto jeho vlastní hodnotu .

Klíčem je myslet na plynulou syntaxi jako na specifickou implementaci jazyka specifického pro doménu. Jako opravdu dobrý příklad toho, o čem mluvím, se podívejte na StoryQ, který využívá plynulost jako prostředek k vyjádření DSL velmi cenným a flexibilním způsobem.

14
S.Robins

Počáteční poznámka: Beru problém s jedním předpokladem v otázce a vyvodím své konkrétní závěry (na konci tento příspěvek). Protože to pravděpodobně neznamená úplnou a obsáhlou odpověď, označuji to jako CW.

Employees.CreateNew().WithFirstName("Peter")…

Lze snadno napsat pomocí inicializátorů, jako jsou:

Employees.Add(new Employee() { FirstName = "Peter", … });

Podle mého názoru by tyto dvě verze měly znamenat a dělat různé věci.

  • Na rozdíl od plynulé verze skrývá plynná verze skutečnost, že nová Employee je také Added do kolekce Employees - pouze naznačuje, že nový objekt je Created.

  • Význam ….WithX(…) je dvojznačný, zejména pro lidi přicházející z F #, který má klíčové slovo with pro výrazy objektů : Mohou interpretovat obj.WithX(x) jako nový nový objekt odvozený z obj, který je totožný s obj s výjimkou jeho vlastnosti X, jejíž hodnota je x. Na druhou stranu je u druhé verze jasné, že nejsou vytvořeny žádné odvozené objekty a že pro původní objekt jsou určeny všechny vlastnosti.

….WithManager().With…
  • Tento ….With… Má ještě jiný význam: přepnutí „fokusu“ inicializace vlastnosti na jiný objekt. Skutečnost, že vaše plynulé API má pro With dva různé významy, je obtížné správně interpretovat, co se děje ... což je možná důvod, proč jste v příkladu použili odsazení, abyste demonstrovali zamýšlený význam tohoto kódu. Bylo by to jasnější takto:

    (employee).WithManager(Managers.CreateNew().WithFirstName("Bill").…)
    //                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //                     value of the `Manager` property appears inside the parentheses,
    //                     like with `WithName`, where the `Name` is also inside the parentheses 
    

Závěry: „Skrývání“ jednoduché jazykové funkce new T { X = x } S plynulým rozhraním API (Ts.CreateNew().WithX(x)) lze samozřejmě udělat, ale:

  1. Je třeba dbát na to, aby čtenáři výsledného plynulého kódu stále chápali, co přesně to dělá. To znamená, že plynulé API by mělo být ve smyslu transparentní a jednoznačné. Navrhování takového API může být více práce, než se očekávalo (možná bude muset být testováno na snadnost použití a přijetí) a/nebo…

  2. navrhnout, že by to mohlo být více práce, než je nutné: V tomto příkladu plynulé API přidává velmi malé „uživatelské pohodlí“ oproti základnímu API (jazyková funkce). Dalo by se říci, že plynulé API by mělo usnadnit použití základní funkce API/jazyka; to znamená, že by to mělo programátorovi ušetřit značné množství úsilí. Pokud je to jen další způsob, jak napsat stejnou věc, pravděpodobně to nestojí za to, protože to životu programátora neusnadňuje, ale pouze ztěžuje práci designéra (viz závěr č. 1 výše).

  3. Oba body výše tiše předpokládají, že plynulé API je vrstva přes existující API nebo jazykovou funkci. Tento předpoklad může být dalším dobrým vodítkem: Plynulé API může být dalším způsobem, jak něco udělat, ne jediným způsobem. To znamená, že by bylo dobrým nápadem nabízet plynné API jako „opt-in“ volbu.

5
stakx

Moc se mi líbí plynulý styl, velmi jasně vyjadřuje záměr. S příkladem, který máte za sebou, musíte mít nastavovače veřejných vlastností, abyste mohli tuto syntaxi používat, nemusíte s plynulým stylem. Řekněme, že s vaším příkladem nezískáte moc nad veřejnými osadníky, protože jste téměř odešli pro metodu Java/esque set/get.

Což mě přivádí k druhému bodu, nejsem si jistý, zda bych použil plynulý styl tak, jak to máš, se spoustou nastavovačů nemovitostí, pravděpodobně bych na to použil druhou verzi. mít spoustu sloves, která se mohou spojit dohromady, nebo alespoň spousty věcí spíše než nastavení.

2
Ian

Nebyl jsem obeznámen s termínem plynulé rozhraní , ale připomíná mi to několik API, které jsem použil, včetně LINQ .

Osobně nevidím, jak by moderní funkce C # bránily užitečnosti takového přístupu. Raději bych řekl, že jdou ruku v ruce. Např. je ještě snazší dosáhnout takového rozhraní pomocí metody rozšíření .

Možná vyjasněte svou odpověď konkrétním příkladem toho, jak lze plynule rozhraní nahradit použitím jedné z moderních funkcí, které jste zmínili.

1
Steven Jeuris