Princip jednotného přístupu - Uniform access principle
![]() | tento článek potřebuje další citace pro ověření.Leden 2010) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
The jednotný princip přístupu z programování byl předložen Bertrand Meyer (původně v Objektově orientovaná konstrukce softwaru ). Uvádí „Všechny služby nabízené a modul by měly být k dispozici prostřednictvím jednotné notace, která nezradí, zda jsou implementovány prostřednictvím úložiště nebo pomocí výpočtu ".[1] Tato zásada platí obecně pro syntax z objektově orientovaný programovací jazyky. V jednodušší formě uvádí, že by mezi prací s programem neměl být žádný syntaktický rozdíl atribut, předem vypočítané vlastnictví nebo metoda /dotaz objektu.
Zatímco většina příkladů se zaměřuje na „čtení“ aspektu principu (tj. Načítání hodnoty), Meyer ukazuje, že s „zápisem“ implikací (tj. Úpravou hodnoty) principu je těžší se vypořádat v jeho měsíčním sloupci na Eiffelovský programovací jazyk oficiální webové stránky.[2]
Vysvětlení
Problém, který Meyer řeší, zahrnuje údržbu velkých softwarových projektů nebo softwarových knihoven. Někdy při vývoji nebo údržbě softwaru je nutné, po zavedení velkého množství kódu, změnit třídu nebo objekt způsobem, který transformuje to, co bylo jednoduše přístupem k atributům, na volání metody. Programovací jazyky často používají jinou syntaxi pro přístup k atributům a pro vyvolání metody (např. něco
proti object.something ()
). Změna syntaxe by vyžadovala v populárních programovacích jazycích dne změnu zdrojového kódu na všech místech, kde byl atribut použit. To může vyžadovat změnu zdrojového kódu na mnoha různých místech ve velmi velkém objemu zdrojového kódu. Nebo ještě horší, pokud je změna v knihovně objektů, kterou používají stovky zákazníků, každý z těchto zákazníků by musel najít a změnit všechna místa, kde byl atribut použit ve svém vlastním kódu, a překompilovat své programy.
Jít obráceně (od metody k jednoduchému atributu) opravdu nebyl problém, protože je možné vždy jen zachovat funkci a nechat ji jednoduše vrátit hodnotu atributu.
Meyer uznal potřebu vývojářů softwaru psát kód takovým způsobem, aby minimalizoval nebo eliminoval kaskádové změny v kódu, které jsou výsledkem změn, které převádějí atribut objektu na volání metody nebo naopak. Za tímto účelem vyvinul princip jednotného přístupu.
Mnoho programovacích jazyků striktně nepodporuje UAP, ale podporuje jeho formy. Vlastnosti, které jsou poskytovány v řadě programovacích jazyků, řeší problém, který Meyer řešil se svým UAP jiným způsobem. Místo toho, aby poskytovaly jedinou jednotnou notaci, poskytují vlastnosti způsob, jak vyvolat metodu objektu při použití stejného zápisu, jaký se používá pro přístup k atributům. Samostatná syntaxe vyvolání metody je stále k dispozici.
Příklad UAP
Pokud jazyk používá syntaxi vyvolání metody, může to vypadat nějak takto.
// Předpokládejme, že tisk zobrazí proměnnou, která mu byla předána, s nebo bez parenů // Nastavte atribut Foo 'bar' na hodnotu 5. Foo.bar (5) print Foo.bar ()
Po spuštění by se mělo zobrazit:
5
Jestli ano nebo ne Foo.bar (5)
vyvolá funkci nebo jednoduše nastaví atribut, který je před volajícím skrytý Foo.bar ()
jednoduše načte hodnotu atributu nebo vyvolá funkci k výpočtu vrácené hodnoty, je implementační detail skrytý volajícímu.
Pokud jazyk používá syntaxi atributu, může syntaxe vypadat takto.
Foo.bar = 5tisk Foo.bar
Znovu, ať už je metoda vyvolána či nikoli, nebo je hodnota jednoduše přiřazena atributu, je skryta před volající metodou.
Problémy
Samotný UAP však může vést k problémům, pokud se používá na místech, kde jsou rozdíly mezi přístupovými metodami ne zanedbatelné, například když je vrácená hodnota nákladná pro výpočet nebo spustí operace mezipaměti.[1]
Jazykové příklady
Rubín
Zvažte následující
y = Vejce.Nový("Zelená")y.barva = "Bílý" uvádí y.barva
Nyní lze třídu Egg definovat následovně
třída Vejce attr_accessor :barva def inicializovat(barva) @barva = barva koneckonec
Výše uvedený počáteční segment kódu by fungoval dobře, kdyby byl Egg definován jako takový. Vaječnou třídu lze také definovat níže, kde barva je místo toho metoda. Volací kód by stále fungoval, beze změny, pokud by měl být Egg definován následujícím způsobem.
třída Vejce def inicializovat(barva) @rgb_color = to_rgb(barva) konec def barva to_color_name(@rgb_color) konec def barva=(barva) @rgb_color = to_rgb(barva) konec soukromé def to_rgb(color_name) ..... konec def to_color_name(barva) .... koneckonec
Všimněte si, jak přesto barva
vypadá jako atribut v jednom případě a dvojice metod v dalším, rozhraní třídy zůstává stejné. Osoba udržující třídu Egg může přepínat z jedné formy do druhé bez obav z porušení kódu volajícího. Ruby se řídí revidovaným UAP, attr_accessor: color
funguje pouze jako syntaktický cukr pro generování přístupových / nastavovacích metod pro barva
. V Ruby neexistuje žádný způsob, jak načíst proměnnou instance z objektu, aniž byste na ni zavolali metodu.
Striktně vzato Ruby nedodržuje původní Meyerův UAP v tom, že syntaxe pro přístup k atributu se liší od syntaxe pro vyvolání metody. Ale zde bude přístup k atributu vždy ve skutečnosti prostřednictvím funkce, která je často automaticky generována. V zásadě tedy každý typ přístupu vyvolává funkci a jazyk se řídí Meyerovým revidovaným Principem jednotného přístupu.
Krajta
Vlastnosti Pythonu lze použít k umožnění vyvolání metody se stejnou syntaxí jako při přístupu k atributu. Zatímco Meyerův UAP by měl jedinou notaci jak pro přístup k atributům, tak pro vyvolání metody (syntaxe vyvolání metody), jazyk s podporou vlastností stále podporuje samostatné notace pro přístup k atributům a metodám. Vlastnosti umožňují použít notaci atributu, ale skrýt fakt, že je vyvolána metoda, místo jednoduchého načtení nebo nastavení hodnoty.
Python jako takový ponechává možnost dodržování UAP na individuálním programátorovi. Integrovaný @vlastnictví
Funkce poskytuje jednoduchý způsob vyzdobit libovolná daná metoda v syntaxi přístupu k atributům, čímž se abstrahuje syntaktický rozdíl mezi vyvoláním metody a přístupem k atributům.[3]
V Pythonu můžeme mít kód, který přistupuje k Vejce
objekt, který lze definovat tak, že váha a barva jsou jednoduché atributy jako v následujícím textu
'''>>> vejce = vejce (4,0, „bílá“)>>> egg.color = "zelená">>> tisk (vejce)Vejce (4,0, zelené)'''třída Vejce: def __init__(já, hmotnost, barva) -> Žádný: já.hmotnost = hmotnost já.barva = barva def __str__(já) -> str: vrátit se F'{__jméno třídy__}({self.weight}, {self.color})'
Nebo objekt Egg může použít vlastnosti a místo toho vyvolat metody getter a setter
# ... (snip) ...třída Vejce: def __init__(já, hmotnost_oz: plovák, color_name: plovák) -> Žádný: já.hmotnost = hmotnost_oz já.barva = color_name @vlastnictví def barva(já) -> str: '' Barva vajíčka '' ' vrátit se to_color_str(já._color_rgb) @barva.seřizovač def barva(já, color_name: str) -> Žádný: já._color_rgb = to_rgb(color_name) @vlastnictví def hmotnost(já) -> plovák: '' Hmotnost v uncích '' ' vrátit se já._ hmotnost_gram / 29.3 @hmotnost.seřizovač def hmotnost(já, hmotnost_oz: plovák) -> Žádný: já._ hmotnost_gram = 29.3 * hmotnost_oz # ... (snip) ...
import webové barvy# třída Vejce:def to_color_str(rgb: webové barvy.Celé čísloRGB) -> str: Snaž se: vrátit se webové barvy.rgb_to_name(rgb) až na ValueError: vrátit se webové barvy.rgb_to_hex(rgb) def to_rgb(color_name: str) -> webové barvy.Celé čísloRGB: Snaž se: vrátit se webové barvy.name_to_rgb(color_name) až na ValueError: vrátit se webové barvy.hex_to_rgb(color_name)-li __název__ == "__hlavní__": import doctest doctest.testmod() |
Bez ohledu na to, jakým způsobem Vejce
je definován, volací kód může zůstat stejný. Implementace Vejce
může přepínat z jednoho formuláře do druhého bez ovlivnění kódu, který používá třídu Egg. Tuto vlastnost mají také jazyky, které implementují UAP.
C#
The C# jazyk podporuje třídu vlastnosti, které poskytují prostředky k definování dostat
a soubor
operace (getry a stavitelé) pro členskou proměnnou. Syntaxe pro přístup nebo úpravu vlastnosti je stejná jako pro přístup k jakékoli jiné proměnné člena třídy, ale skutečnou implementaci lze definovat buď jako jednoduchý přístup pro čtení / zápis nebo jako funkční kód.
veřejnost třída Foo{ soukromé tětiva _název; // Vlastnictví veřejnost int Velikost { dostat; // Getter soubor; // Setr } // Vlastnictví veřejnost tětiva název { dostat { vrátit se _název; } // Getter soubor { _název = hodnota; } // Setr }}
Ve výše uvedeném příkladu třída Foo
obsahuje dvě vlastnosti, Velikost
a název
. The Velikost
vlastnost je celé číslo, které lze číst (získávat) a zapisovat (nastavovat). Podobně název
property je řetězec, který lze také číst a upravovat, ale jeho hodnota je uložena v samostatné (soukromé) proměnné třídy _název
.
Vynechání soubor
operace v definici vlastnosti způsobí, že vlastnost bude jen pro čtení, zatímco vynechá dostat
operace umožňuje pouze zápis.
Použití vlastností využívá UAP, jak je znázorněno v níže uvedeném kódu.
veřejnost Foo CreateFoo(int velikost, tětiva název) { var foo = Nový Foo(); foo.Velikost = velikost; // Nastavovač vlastností foo.název = název; // Nastavovač vlastností vrátit se foo; }
C ++
C ++ nemá ani UAP, ani vlastnosti, když se objekt změní tak, že se atribut (barva) stane dvojicí funkcí (getA, setA). Jakékoli místo, které používá instanci objektu, a buď nastaví nebo získá hodnotu atributu (x = obj. barva
nebo obj.color = x
) je nutné změnit, aby se vyvolala jedna z funkcí. (x = obj.getColor ()
nebo obj.setColor (x)
). Pomocí šablon a přetížení operátora je možné falešné vlastnosti, ale je to složitější než v jazycích, které vlastnosti přímo podporují. To komplikuje údržbu programů v C ++. Distribuované knihovny objektů C ++ musí být opatrné, jak poskytují přístup k datům členů.
JavaScript
JavaScript má podporu pro vypočítané vlastnosti od roku 2009.[4]
Shell nové generace
V prostředí Next Generation Shell se přístup k polím objektu provádí prostřednictvím .
syntaxe, podobně jako u jiných programovacích jazyků. V souladu se zbytkem jazyka je syntaxe zkratkou pro vyvolání metody. myobj.myfield
je interpretováno jako volání metody .
s argumenty myobj
a Myfield
.
Integrovaná implementace .
vrací hodnotu pole z paměťového místa vyhrazeného výhradně pro dané pole instance konkrétního objektu. Chcete-li přizpůsobit chování .
pro konkrétní typ je třeba definovat metodu s názvem .
pro tento typ.
Podobně, .=
metoda je požadována myobj.myfield = myval
syntax.
Následující příklad ukazuje výchozí chování .
a .=
metody.
typ EggF init(e: Vejce, barva: Str) {e. barva = barva}E = Vejce("Zelená")e. barva = "Bílý"echo(e. barva)
Následující příklad ukazuje přizpůsobené chování .
a .=
metody. Kód implementuje přístupový objekt pro barva
pole.
typ EggF init(e: Vejce, barva: Str) {e.rgb_color = RGBColor(barva)}F.(e: Vejce, pole: Str) {hlídat pole == 'barva'e.rgb_color.name()}F.=(e: Vejce, pole: Str, hodnota: Str) {hlídat pole == 'barva'e.rgb_color = RGBColor(hodnota)}E = Vejce("Zelená")e. barva = "Bílý"echo(e. barva)
Reference
- ^ A b „Princip UniformAccess“. c2 wiki. Citováno 6. srpna 2013.
- ^ Meyer, Bertrand. „Sloup EiffelWorld: Business plus potěšení“. Citováno 6. srpna 2013.
- ^ Oficiální dokumenty v Pythonu, vestavěné funkce
- ^ w3schools.com, Přistupující k Javascriptům