Das Prinzip des einheitlichen Zugriffs in der Computerprogrammierung wurde von Bertrand Meyer (ursprünglich in seinem Buch „Object-Oriented Software Construction “) formuliert . Es besagt: „Alle von einem Modul angebotenen Dienste sollten über eine einheitliche Notation zugänglich sein, die nicht erkennen lässt, ob sie durch Speicherung oder Berechnung implementiert sind.“ [ 1 ] [ 2 ] Dieses Prinzip gilt allgemein für die Syntax objektorientierter Programmiersprachen . Vereinfacht ausgedrückt besagt es , dass es keinen syntaktischen Unterschied zwischen der Arbeit mit einem Attribut , einer vorab berechneten Eigenschaft oder einer Methode / Abfrage eines Objekts geben sollte .

Während sich die meisten Beispiele auf den „Lese“-Aspekt des Prinzips konzentrieren (d. h. das Abrufen eines Wertes), zeigt Meyer in seiner monatlichen Kolumne auf der offiziellen Website der Programmiersprache Eiffel , dass die „Schreib“-Implikationen (d. h. das Ändern eines Wertes) des Prinzips schwieriger zu handhaben sind . [ 3 ]

Erläuterung

Das von Meyer angesprochene Problem betrifft die Wartung großer Softwareprojekte oder Softwarebibliotheken. Bei der Softwareentwicklung oder -wartung ist es mitunter notwendig, nach umfangreichem Code eine Klasse oder ein Objekt so zu ändern, dass ein einfacher Attributzugriff in einen Methodenaufruf umgewandelt wird. Programmiersprachen verwenden oft unterschiedliche Syntaxen für den Attributzugriff und den Methodenaufruf (z. B. `std::attribute` vs. ` object.somethingstd:: object.something()method`). In den damals gängigen Programmiersprachen würde die Syntaxänderung eine Anpassung des Quellcodes an allen Stellen erfordern, an denen das Attribut verwendet wird. Dies könnte Änderungen an vielen verschiedenen Stellen in einem sehr großen Quellcodeumfang notwendig machen. Schlimmer noch: Betrifft die Änderung eine Objektbibliothek, die von Hunderten von Kunden genutzt wird, müsste jeder dieser Kunden alle Stellen in seinem eigenen Code finden, ändern und seine Programme neu kompilieren.

Der umgekehrte Weg (von der Methode zum einfachen Attribut) war eigentlich kein Problem, da man immer einfach die Funktion beibehalten und sie den Attributwert zurückgeben lassen kann.

Meyer erkannte die Notwendigkeit für Softwareentwickler, Code so zu schreiben, dass kaskadierende Codeänderungen, die durch die Umwandlung eines Objektattributs in einen Methodenaufruf oder umgekehrt entstehen, minimiert oder vermieden werden. Zu diesem Zweck entwickelte er das Prinzip des einheitlichen Zugriffs.

Viele Programmiersprachen unterstützen das UAP nicht vollständig, aber in abgewandelter Form. Eigenschaften, die in zahlreichen Programmiersprachen verfügbar sind, lösen das Problem, das Meyer mit seinem UAP anging, auf andere Weise. Anstatt eine einheitliche Notation bereitzustellen, ermöglichen Eigenschaften den Aufruf einer Objektmethode mit derselben Notation wie beim Attributzugriff. Die separate Syntax für Methodenaufrufe bleibt weiterhin verfügbar.

UAP-Beispiel

Wenn die Sprache die Methodenaufrufsyntax verwendet, könnte das etwa so aussehen:

// Es wird davon ausgegangen, dass print die übergebene Variable ausgibt, mit oder ohne Klammern. // Setze das Attribut 'bar' von Foo auf den Wert 5. Foo.bar(5) print Foo.bar() 

Bei der Ausführung sollte Folgendes angezeigt werden:

5 

Ob Foo.bar(5)eine Funktion aufgerufen oder lediglich ein Attribut gesetzt wird, ist für den Aufrufer nicht ersichtlich. Ebenso Foo.bar()ist es ein Implementierungsdetail, ob der Wert des Attributs einfach abgerufen oder eine Funktion zur Berechnung des Rückgabewerts aufgerufen wird.

Wenn die Sprache die Attributsyntax verwendet, könnte die Syntax folgendermaßen aussehen:

Foo.bar = 5 print Foo.bar 

Auch hier bleibt es für die aufrufende Methode verborgen, ob eine Methode aufgerufen wird oder ob der Wert einfach einem Attribut zugewiesen wird.

Probleme

Allerdings kann UAP selbst zu Problemen führen, wenn es an Stellen eingesetzt wird, an denen die Unterschiede zwischen den Zugriffsmethoden nicht vernachlässigbar sind, beispielsweise wenn die Berechnung des zurückgegebenen Werts aufwändig ist oder Cache-Operationen auslöst. [ 2 ]

Sprachbeispiele

Python

Python-Properties ermöglichen es, Methoden mit derselben Syntax wie Attribute aufzurufen. Während Meyers UAP eine einheitliche Notation für Attributzugriff und Methodenaufruf (Methodenaufrufsyntax) vorsieht, unterstützt eine Sprache mit Properties-Unterstützung weiterhin separate Notationen für Attribut- und Methodenzugriff. Properties erlauben die Verwendung der Attributnotation, verschleiern aber gleichzeitig, dass eine Methode aufgerufen wird, anstatt lediglich einen Wert abzurufen oder zu setzen.

Python überlässt es daher dem einzelnen Programmierer, sich an das UAP-Prinzip zu halten. Die integrierte @propertyFunktion bietet eine einfache Möglichkeit, jede beliebige Methode mit der Syntax für Attributzugriffe zu versehen und so den syntaktischen Unterschied zwischen Methodenaufrufen und Attributzugriffen zu abstrahieren. [ 4 ]

In Python kann Code auf ein EggObjekt zugreifen, das so definiert werden kann, dass Gewicht und Farbe einfache Attribute sind, wie im folgenden Beispiel:

""" >>> egg = Egg(4.0, "white") >>> egg.color = "green" >>> print(egg) Egg(4.0, green) """class Egg : def __init__ ( self , weight , color ) -> None : self . weight = weight self . color = colordef __str__ ( self ) -> str : return f " { __class__ . __name__ } ( { self . weight } , { self . color } )"

Oder das Egg-Objekt könnte Eigenschaften verwenden und stattdessen Getter- und Setter-Methoden aufrufen.

# ...(Auszug)... class Egg : def __init__ ( self , weight_oz : float , color_name : float ) -> None : self . weight = weight_oz self . color = color_name@property def color ( self ) -> str : """Farbe des Eis.""" return to_color_str ( self . _color_rgb )@ color.setter def color ( self , color_name : str ) - > None : self._color_rgb = to_rgb ( color_name )​​@property def weight ( self ) -> float : """Gewicht in Unzen.""" return self . _weight_gram / 29.3@ weight.setter def weight ( self , weight_oz : float ) - > None : self._weight_gram = 29.3 * weight_oz​​# ...(Auszug)...
Die ausgeschnittenen Codes lauten wie folgt:
Webfarben importieren# Klasse Ei:def to_color_str ( rgb : webcolors.IntegerRGB ) - > str : try : return webcolors.rgb_to_name ( rgb ) except ValueError : return webcolors.rgb_to_hex ( rgb )​​​​​def to_rgb ( color_name : str ) - > webcolors.IntegerRGB : try : return webcolors.name_to_rgb ( color_name ) except ValueError : return webcolors.hex_to_rgb ( color_name )​​​​​if __name__ == "__main__" : import doctest doctest . testmod ()

Unabhängig davon, welche Methode Eggdefiniert ist, kann der aufrufende Code unverändert bleiben. Die Implementierung Eggkann zwischen den beiden Formen wechseln, ohne Code zu beeinträchtigen, der die Egg-Klasse verwendet. Sprachen, die das UAP implementieren, weisen diese Eigenschaft ebenfalls auf.

Rubin

Betrachten Sie Folgendes

y = Egg.new ( " Grün " ) y.color = " Weiß " puts y.color​​

Die Egg-Klasse könnte nun wie folgt definiert werden:

class Egg attr_accessor :color def initialize ( color ) @color = color end end

Der obige Codeabschnitt würde mit der gegebenen Definition von `Egg` einwandfrei funktionieren. Die Klasse `Egg` könnte aber auch wie folgt definiert werden, wobei `color` eine Methode ist. Der aufrufende Code würde weiterhin unverändert funktionieren, wenn `Egg` wie folgt definiert würde.

class Egg def initialize ( color ) @rgb_color = to_rgb ( color ) enddef color to_color_name ( @rgb_color ) end def color= ( color ) @rgb_color = to_rgb ( color ) endprivate def to_rgb ( color_name ) ..... enddef to_color_name ( color ) .... end end

colorBeachten Sie, dass die Schnittstelle zur Klasse unverändert bleibt, obwohl `` in einem Fall wie ein Attribut und im nächsten wie ein Methodenpaar aussieht. Derjenige, der die `Egg`-Klasse verwaltet, kann zwischen den beiden Darstellungsformen wechseln, ohne befürchten zu müssen, den Code anderer Aufrufer zu beeinträchtigen. Ruby folgt dem überarbeiteten UAP; attr_accessor :color``` dient lediglich als syntaktischer Zucker zur Generierung von Zugriffs- und Settermethoden für `` color. In Ruby gibt es keine Möglichkeit, eine Instanzvariable eines Objekts abzurufen, ohne eine Methode darauf aufzurufen.

Streng genommen folgt Ruby nicht Meyers ursprünglichem UAP, da die Syntax für den Zugriff auf ein Attribut sich von der Syntax für den Aufruf einer Methode unterscheidet. Der Zugriff auf ein Attribut erfolgt hier jedoch immer über eine Funktion, die häufig automatisch generiert wird. Im Wesentlichen ruft also jede Zugriffsart eine Funktion auf, und die Sprache folgt Meyers überarbeitetem Uniform Access Principle.

C#

Die Programmiersprache C# unterstützt Klasseneigenschaften , mit denen sich Zugriffsmethoden ( Getter und Setter ) für eine Membervariable definieren getund anwenden lassen . Die Syntax für den Zugriff auf oder die Änderung einer solchen Eigenschaft entspricht der Syntax für den Zugriff auf jede andere Klassenmembervariable. Die eigentliche Implementierung kann jedoch entweder als einfacher Lese-/Schreibzugriff oder als funktionaler Code definiert werden. set

public class Foo { private string _name ;// Eigenschaft public int Size { get ; // Getter set ; // Setter }// Eigenschaft public string Name { get { return _name ; } // Getter set { _name = value ; } // Setter } }

Im obigen Beispiel Fooenthält die Klasse zwei Eigenschaften: `integer` Sizeund Name`set`. Die SizeEigenschaft `integer` ist eine Ganzzahl, die gelesen (get) und geschrieben (set) werden kann. Die NameEigenschaft `set` ist analog dazu eine Zeichenkette, die ebenfalls gelesen und geändert werden kann, deren Wert jedoch in einer separaten (privaten) Klassenvariable gespeichert wird _name.

Wird die setOperation in einer Eigenschaftsdefinition weggelassen, ist die Eigenschaft schreibgeschützt; wird die getOperation weggelassen, ist sie schreibgeschützt.

Die Verwendung der Eigenschaften erfolgt über die UAP, wie im folgenden Codebeispiel gezeigt.

public Foo CreateFoo ( int size , string name ) { var foo = new Foo (); foo . Size = size ; // Eigenschaftssetter foo . Name = name ; // Eigenschaftssetter return foo ; }

C++

C++ kennt weder das UAP noch Eigenschaften. Wenn ein Objekt so verändert wird, dass ein Attribut (z. B. Farbe) zu einem Funktionspaar ( getA, setA ) wird, muss jede Stelle im Code, die eine Instanz des Objekts verwendet und den Attributwert setzt oder abruft, x = obj.colorangepasst obj.color = xwerden, um eine der Funktionen aufzurufen. Mithilfe von Templates und Operatorüberladungx = obj.getColor() lassen sich Eigenschaften zwar simulieren, dies ist jedoch komplexer als in Sprachen , die Eigenschaften direkt unterstützen. Dies erschwert die Wartung von C++-Programmen. Verteilte Bibliotheken von C++-Objekten müssen daher sorgfältig darauf achten, wie sie den Zugriff auf Memberdaten ermöglichen. obj.setColor(x)

JavaScript

JavaScript unterstützt berechnete Eigenschaften über Getter und Setter seit ECMAScript 5 im Jahr 2009. [ 5 ] Es gibt jedoch Sonderfälle, wie zum Beispiel die lengthEigenschaft `on` Array.prototype, String.prototypedie bereits vor ECMAScript 5 existierten. [ 6 ]

In ECMAScript 5 JavaScript Object.definePropertykönnen Getter und Setter definiert werden. [ 7 ] Zum Beispiel:

var obj = {};Object.defineProperty ( obj , "two" , { "get" : function () { return 1 + 1 ; } } ) ;

Anschließend obj.twokann die Getter-Funktion ausgeführt werden. Da die Eigenschaft twokeinen Setter definiert, führt jeder Schreibvorgang in die Eigenschaft zu keiner Operation . Für einen Setter setwird stattdessen die Eigenschaft verwendet:

var obj = {};Object.defineProperty ( obj , " two " , { "get" : function ( ) { return this.x ; } , "set" : function () { this.x = 1 + 1 ; } } ) ;

Referenzen

  1. ^ Meyer, Bertrand (1997). Objektorientierte Softwareentwicklung (2. Aufl.). Prentice Hall. S. 57. ISBN 978-0-13-629155-8Die
  2. ^ a b „Das UniformAccessPrinciple“ . c2 wiki . Abgerufen am 6. August 2013 .
  3. ^ Meyer, Bertrand. „EiffelWorld-Kolumne: Geschäft und Vergnügen“ . Abgerufen am 6. August 2013 .
  4. ^ Offizielle Python-Dokumentation, integrierte Funktionen
  5. ^ „ECMA-262, 5. Auflage, Dezember 2009“ (PDF) . ECMA International . Dezember 2009. Abgerufen am 15. Juli 2025 .
  6. ^ „ECMAScript Language Specification“ (PDF) . ECMA International . 24. März 2000. Abgerufen am 15. Juli 2025 .
  7. ^ „Object.defineProperty() - JavaScript“ . Mozilla . Abgerufen am 15. Juli 2025 .