Klassen benennen - Wie vermeide ich, alles als "<WhatEver> Manager" zu bezeichnen? [geschlossen]


1188

Vor langer Zeit habe ich einen Artikel gelesen (ich glaube ein Blogeintrag), der mich auf die "richtige" Spur beim Benennen von Objekten gebracht hat: Seien Sie sehr, sehr gewissenhaft beim Benennen von Dingen in Ihrem Programm.

Wenn meine Anwendung beispielsweise (als typische Geschäftsanwendung) Benutzer, Unternehmen und Adressen handhaben würde, hätte ich eine User, eine Companyund eine AddressDomänenklasse - und wahrscheinlich würde irgendwo ein UserManager, ein CompanyManagerund ein AddressManagerauftauchen, das diese Dinge behandelt.

So kann man sagen , was diejenigen UserManager, CompanyManagerund AddressManagertun? Nein, denn Manager ist ein sehr allgemeiner Begriff, der zu allem passt, was Sie mit Ihren Domänenobjekten tun können.

In dem Artikel, den ich gelesen habe, wurde empfohlen, sehr spezifische Namen zu verwenden. Wenn es sich um eine C ++ - Anwendung handelte und der UserManagerJob darin bestand, Benutzer zuzuweisen und vom Heap zu befreien, würde er die Benutzer nicht verwalten, sondern ihre Geburt und ihren Tod schützen. Hmm, vielleicht könnten wir das a nennen UserShepherd.

Oder vielleicht besteht die UserManagerAufgabe darin, die Daten jedes Benutzerobjekts zu untersuchen und die Daten kryptografisch zu signieren. Dann hätten wir eine UserRecordsClerk.

Jetzt, wo diese Idee bei mir geblieben ist, versuche ich sie anzuwenden. Und finde diese einfache Idee erstaunlich schwer.

Ich kann beschreiben, was die Klassen tun, und (solange ich nicht in die schnelle und schmutzige Codierung schlüpfe) die Klassen, die ich schreibe, genau eines tun. Was ich vermisse, um von dieser Beschreibung zu den Namen zu gelangen, ist eine Art Katalog von Namen, ein Vokabular, das die Konzepte Namen zuordnet.

Letztendlich möchte ich so etwas wie einen Musterkatalog im Kopf haben (häufig liefern Entwurfsmuster leicht die Objektnamen, z. B. eine Fabrik ).

  • Factory - Erstellt andere Objekte (Benennung aus dem Entwurfsmuster)
  • Hirte - Ein Hirte kümmert sich um die Lebensdauer von Objekten, deren Entstehung und Abschaltung
  • Synchronizer - Kopiert Daten zwischen zwei oder mehr Objekten (oder Objekthierarchien).
  • Kindermädchen - Hilft Objekten, nach der Erstellung den Status "verwendbar" zu erreichen - beispielsweise durch Verkabelung mit anderen Objekten

  • etc etc. etc.

Wie gehen Sie mit diesem Problem um? Haben Sie einen festen Wortschatz, erfinden Sie spontan neue Namen oder denken Sie darüber nach, Dinge zu benennen, die nicht so wichtig oder falsch sind?

PS: Ich interessiere mich auch für Links zu Artikeln und Blogs, die das Problem diskutieren. Hier ist zunächst der ursprüngliche Artikel, über den ich nachgedacht habe: Benennen von Java-Klassen ohne 'Manager'


Update: Zusammenfassung der Antworten

Hier ist eine kleine Zusammenfassung dessen, was ich in der Zwischenzeit aus dieser Frage gelernt habe.

  • Versuche keine neuen Metaphern zu erstellen (Nanny)
  • Schauen Sie sich an, was andere Frameworks tun

Weitere Artikel / Bücher zu diesem Thema:

Und eine aktuelle Liste von Namenspräfixen / -suffixen, die ich (subjektiv!) Aus den Antworten gesammelt habe:

  • Koordinator
  • Baumeister
  • Schriftsteller
  • Leser
  • Handler
  • Container
  • Protokoll
  • Ziel
  • Konverter
  • Regler
  • Aussicht
  • Fabrik
  • Entität
  • Eimer

Und ein guter Tipp für die Straße:

Keine Namenslähmung. Ja, Namen sind sehr wichtig, aber sie sind nicht wichtig genug, um viel Zeit damit zu verschwenden. Wenn Sie sich in 10 Minuten keinen guten Namen ausdenken können, fahren Sie fort.


11
Es gehört in das Community-Wiki, weil es keine "beste" Antwort gibt. Es ist eine Diskussion.
DOK

13
Das ist nicht intuitiv. Sollten sie es nicht ein Forum nennen? Ich würde denken, ein Wiki wäre für eine Sammlung von Fakten, nicht für Meinungen.
AaronLS

78
Vielen Dank, dass Sie dies auf dem neuesten Stand halten - aber dieser letzte Tipp ist ein schrecklicher Rat! Wenn Ihnen in 10 Minuten kein guter Name einfällt, stimmt wahrscheinlich etwas mit Ihrer Klasse nicht. (Mit den üblichen Einschränkungen: 1) Perfekt ist der Feind des Guten, 2) Versand ist eine Funktion - denken Sie daran, dass Sie technische Schulden haben.)
Jeff Sternal

11
Wenn Sie sich in 10 Minuten keinen guten Namen ausdenken können, bitten Sie Ihren Kollegen um Hilfe. Gib nicht einfach auf.

9
Wenn Sie sich in 10 Minuten keinen guten Namen ausdenken können, erklären Sie ihn Ihren Kollegen. Sie denken vielleicht an einen guten Namen (user338195), aber wenn Sie versuchen, ihn zu erklären, können Sie wahrscheinlich herausfinden, was daran falsch ist ( Jeff ).
WillC

Antworten:


204

Ich habe eine ähnliche Frage gestellt , aber wenn möglich, versuche ich, die Namen bereits im .NET Framework zu kopieren , und suche nach Ideen in den Java- und Android- Frameworks.

Es scheint Helper, Managerund Utilsind die unvermeidlichen Substantive, die Sie für die Koordinierung von Klassen anhängen, die keinen Status enthalten und im Allgemeinen prozedural und statisch sind. Eine Alternative ist Coordinator.

Sie könnten sich vor allem lila prosey mit den Namen und gehen für Dinge wie Minder, Overseer, Supervisor, Administrator, und Master, aber wie gesagt , ich es wie die Rahmen Namen lieber halten Sie es gewohnt sind.


Einige andere gebräuchliche Suffixe (wenn dies der richtige Begriff ist), die Sie auch im .NET Framework finden, sind:

  • Builder
  • Writer
  • Reader
  • Handler
  • Container

4
Ich mag diese sehr. Sie geraten nicht in die Falle schlechter oder unbekannter Metaphern, da sie bereits von .NET Framework verwendet werden. Es könnte interessant sein, sich auch andere Bibliotheken (Java) anzusehen, um mehr über die häufig verwendeten Informationen zu erfahren.
froh42

Ich möchte vorschlagen Conductor, wie der Dirigent eines Musikorchesters. Es ist sicherlich eine wichtige Rolle, abhängig von der Art der Kollaborationen, die Sie "durchführen" müssen (andere Objekte sind sehr spezialisierte Akteure, die auf zentralisierte Befehle reagieren und sich nicht zu viele Sorgen um jeden anderen Kollaborateur machen sollten).
Heltonbiker

1
Ich glaube nicht, dass die Lösung für -er Klassen darin besteht, einen anderen Namen zu finden. Wie ich in vielen anderen Beiträgen gelesen habe und versucht habe, die Antwort zu erfahren, müssen Sie die Architektur ändern, nicht nur den verwendeten Namen.
Michael Ozeryansky

115

Sie können einen Blick auf source-code-wordle.de werfen . Ich habe dort die am häufigsten verwendeten Suffixe von Klassennamen des .NET Frameworks und einiger anderer Bibliotheken analysiert.

Die Top 20 sind:

  • Attribut
  • Art
  • Helfer
  • Sammlung
  • Konverter
  • Handler
  • die Info
  • Anbieter
  • Ausnahme
  • Bedienung
  • Element
  • Manager
  • Knoten
  • Möglichkeit
  • Fabrik
  • Kontext
  • Artikel
  • Designer
  • Base
  • Editor

147
In einem bestimmten Unternehmen kannte ich vor langer Zeit einen Ingenieur, der die absurde und wachsende Fülle von Suffix-Regeln, die das Unternehmen plagten, so satt hatte, dass er trotzig jede Klasse beendete Thingy.

8
Diese Liste von Namen an sich ist nicht so nützlich, ohne deren Kontext das Suffix angewendet werden sollte.
Fred

65

Ich bin alles für gute Namen, und ich schreibe oft darüber, wie wichtig es ist, bei der Auswahl von Namen für Dinge sehr vorsichtig zu sein. Aus dem gleichen Grund bin ich vorsichtig bei Metaphern, wenn ich Dinge benenne. In der ursprünglichen Frage sehen "Fabrik" und "Synchronisierer" wie gute Namen für das aus, was sie zu bedeuten scheinen. "Hirte" und "Kindermädchen" sind es jedoch nicht, weil sie auf Metaphern basieren . Eine Klasse in Ihrem Code kann nicht buchstäblich ein Kindermädchen sein. Sie nennen es ein Kindermädchen, weil es sich um einige andere Dinge kümmert, ähnlich wie ein echtes Kindermädchen sich um Babys oder Kinder kümmert. Das ist in informeller Sprache in Ordnung, aber (meiner Meinung nach) nicht in Ordnung, um Klassen in Code zu benennen, die von wem weiß wen wen wann gepflegt werden müssen.

Warum? Weil Metaphern kulturabhängig und oft auch individuell abhängig sind. Für Sie kann es sehr klar sein, eine Klasse "Kindermädchen" zu nennen, aber für andere ist es vielleicht nicht so klar. Darauf sollten wir uns nicht verlassen, es sei denn, Sie schreiben Code, der nur für den persönlichen Gebrauch bestimmt ist.

In jedem Fall kann Konvention eine Metapher machen oder brechen. Die Verwendung von "factory" selbst basiert auf einer Metapher, die es aber schon eine ganze Weile gibt und die derzeit in der Programmierwelt ziemlich bekannt ist. Daher würde ich sagen, dass die Verwendung sicher ist. "Kindermädchen" und "Hirte" sind jedoch inakzeptabel.


10
Dieses Argument bricht wirklich darin zusammen, dass Factory selbst offensichtlich eine Metapher ist. Oft klären Metaphern wirklich, wozu ein Objekt gut sein könnte, während vage oder generisch automatisch sicherstellt, dass der einzige Weg, um herauszufinden, was der Code tut, darin besteht, ihn vollständig zu lesen! Das schlimmste Szenario.
Kzqai

1
+1, um 'süße' Namen zu vermeiden. Ich finde es großartig, so direkt mit der Sprache umzugehen, wie du nur kannst. (Natürlich ist es nicht immer einfach, gleichzeitig direkt, prägnant, präzise und eindeutig zu sein…)
andrewf

1
Eine erfinderische Wahl von Verb + "er" wird für konkrete Klassen normalerweise klarer sein als eine farbenfrohe Analogie. Neue Abstraktionen hingegen - Dinge, die ein neues Konzept sind, eine neue "Art von Dingen" und nicht nur eine neue "Sache" - eignen sich oft gut als Metaphern (Javas "Bohnen", Haskells "Linsen", GUI "Windows", "Versprechen" vieler Sprachen). Die meisten Codebasen haben jedoch keine echten Erfindungen.
Malnormalulo

51

Wir konnten tun ohne xxxFactory, xxxManageroder xxxRepositoryKlassen , wenn wir die reale Welt korrekt modelliert:

Universe.Instance.Galaxies["Milky Way"].SolarSystems["Sol"]
        .Planets["Earth"].Inhabitants.OfType<Human>().WorkingFor["Initech, USA"]
        .OfType<User>().CreateNew("John Doe");

;-);


11
Wie würden Sie zu parallelen Universen und alternativen Dimensionen gelangen?
Tster

23
Das ist einfach: Omniverse.Instance.Dimensions ["Ours"]. Universes ["Ours"]. Galaxies ... ... okay, okay, ich gebe zu, dies würde eine Neukompilierung erfordern. ;-)
Herzmeister

73
Update: Dies wurde in .NET 4.0 hinzugefügt : Universe.Instance.ToParallel();)
Connell

2
Verstößt jedoch gegen das Demeter-Gesetz!
Jonas G. Drange

13
Das sind Objekte und Mitglieder, keine
Harry Berry

39

Es klingt wie ein rutschiger Hang zu etwas, das auf thedailywtf.com, "ManagerOfPeopleWhoHaveMortgages" usw. veröffentlicht wird.

Ich nehme an, es ist richtig, dass eine monolithische Manager-Klasse kein gutes Design ist, aber die Verwendung von 'Manager' ist nicht schlecht. Anstelle von UserManager wird es möglicherweise in UserAccountManager, UserProfileManager, UserSecurityManager usw. unterteilt.

'Manager' ist ein gutes Wort, weil es deutlich zeigt, dass eine Klasse kein reales 'Ding' darstellt. 'AccountsClerk' - Wie soll ich feststellen, ob dies eine Klasse ist, die Benutzerdaten verwaltet oder jemanden repräsentiert, der für seinen Job ein Account Clerk ist?


8
Was ist mit UserAccounter, UserProfiler und UserSecurer? Wenn Sie Manager loswerden, müssen Sie sich eine spezifische Definition einfallen lassen, was ich für eine gute Sache halte.
Didier A.

10
Was ist mit UserAccount, UserProfile, UserSecurity oO?
Klima

3
Ich würde es "MortageOwnersManager" nennen
volter9

Manchmal hat die Domain bestimmte Namen. Wie "MortageHolder" ist das vielleicht besser als "MortageOwner"
Borjab


24

Wenn ich über die Verwendung von Manageroder Helperin einem Klassennamen nachdenke , halte ich es für einen Codegeruch, der bedeutet, dass ich noch nicht die richtige Abstraktion gefunden habe und / oder gegen das Prinzip der Einzelverantwortung verstoße , also umgestalte und mehr Aufwand in das Design stecke oft erleichtert das Benennen viel.

Aber selbst gut gestaltete Klassen benennen sich nicht (immer) selbst, und Ihre Auswahl hängt teilweise davon ab, ob Sie Geschäftsmodellklassen oder Klassen für technische Infrastruktur erstellen.

Geschäftsmodellklassen können schwierig sein, da sie für jede Domäne unterschiedlich sind. Es gibt einige Begriffe, die ich häufig verwende, Policyz. B. für Strategieklassen innerhalb einer Domäne (z. B. LateRentalPolicy), aber diese ergeben sich normalerweise aus dem Versuch, eine " allgegenwärtige Sprache " zu erstellen , die Sie mit Geschäftsbenutzern teilen können, und dem Entwerfen und Benennen von Klassen, damit diese real modellieren -Weltideen, Objekte, Aktionen und Ereignisse.

Technische Infrastrukturklassen sind etwas einfacher, da sie Domänen beschreiben, die wir sehr gut kennen. Ich ziehe es vor, Entwurfsmusternamen in die Klassennamen aufzunehmen, wie InsertUserCommand, CustomerRepository,oder SapAdapter.ich verstehe die Besorgnis über die Kommunikation der Implementierung anstelle von Absichten, aber Entwurfsmuster verbinden diese beiden Aspekte des Klassendesigns - zumindest, wenn Sie sich mit Infrastruktur befassen, wo Sie die wollen Umsetzung Design transparent zu sein , auch wenn Sie die Details versteckt sind.


1
Ich mag die Idee wirklich, das PolicySuffix für Klassen zu verwenden, die Geschäftslogik enthalten
jtate

+1 für die Erwähnung des Codegeruchs, der mit Namen wie "Manager" und "Helfer" verbunden ist. Ich stelle fest, dass wenn ich keine klaren Namen für Dinge habe, dies normalerweise zumindest teilweise auf eine gewisse Unschärfe in meinem Verständnis der Domäne zurückzuführen ist, sei es geschäftlich oder technisch. Fast gleichwertig könnte dies bedeuten, dass ich Klassen nur reaktiv aufteile, weil sie "zu groß" geworden sind - was für mich auch ein Zeichen für unzureichende Modellierung ist. Dies sollte die am besten gewählte Antwort sein.
nclark

10

Wenn ich mit Mustern, wie sie im GOF-Buch definiert sind , vertraut bin und Objekte danach benenne, kann ich Klassen gut benennen, organisieren und Absichten kommunizieren. Die meisten Menschen werden diese Nomenklatur (oder zumindest einen Großteil davon) verstehen.


Fowler ist eine gute Referenz für mich, aber der GOF ist eine großartige Empfehlung.
Lazarus

Vergib mir meine Unwissenheit. Auf welches Fowler-Buch beziehen Sie sich?
Brian Agnew


19
Hmm, manchmal funktioniert das (zum Beispiel wie eine Fabrik oder eine Strategie), aber manchmal habe ich das Gefühl, dass dies die Art der Implementierung (ich habe ein Muster verwendet!) Mehr kommuniziert als die Absicht und Aufgabe der Klasse. Zum Beispiel ist das Wichtigste für einen Singleton das, was er darstellt - und nicht, dass es ein Singleton ist. Eine strikte Benennung nach den verwendeten Mustern fühlt sich also wie eine strikte Benennung nach den verwendeten Typen an. Zum Beispiel die ungarische Notation, die von der Windows-
Systemgruppe

1
Für technische Infrastrukturklassen ist es normalerweise wünschenswert, die Implementierung transparent zu machen - und die meisten kanonischen Entwurfsmusternamen kommunizieren sowohl Implementierung als auch Absicht. Domänenmodellklassen sind jedoch eine andere Sache.
Jeff Sternal

10

Wenn ich keinen konkreteren Namen für meine Klasse als XyzManager finden kann, wäre dies ein Punkt für mich, um zu überdenken, ob dies wirklich eine Funktionalität ist, die in einer Klasse zusammengehört, dh ein architektonischer „Code-Geruch“.


8

Ich denke, das Wichtigste ist: Ist der Name beschreibend genug? Kannst du anhand des Namens erkennen, was die Klasse tun soll? Die Verwendung von Wörtern wie "Manager", "Service" oder "Handler" in Ihren Klassennamen kann als zu allgemein angesehen werden. Da jedoch viele Programmierer sie verwenden, hilft es auch, zu verstehen, wofür die Klasse gedacht ist.

Ich selbst habe das Fassadenmuster oft benutzt (zumindest denke ich, dass es so heißt). Ich könnte eine UserKlasse haben, die nur einen Benutzer beschreibt, und eine UsersKlasse, die meine "Sammlung von Benutzern" verfolgt. Ich nenne die Klasse nicht a, UserManagerweil ich Manager im wirklichen Leben nicht mag und nicht daran erinnert werden möchte :) Die einfache Verwendung der Pluralform hilft mir zu verstehen, was die Klasse tut.


Ich mag diesen Ansatz auch sehr, weil er die Idee der Top-Down-Verwaltung von Objekten erleichtert. Eine Gruppe von Benutzern impliziert eher, dass die Arbeit zwischen Benutzern statt über den UserManager ausgeführt wird. Außerdem ist es nicht so seltsam, wenn ein Benutzer einen Verweis auf Benutzer besitzt, wie wenn er UserManager besitzt. Es ist offener für relatives Denken als für OOP.
Seph Reed

Das Problem bei diesem Ansatz ist, dass es sehr schwierig wird, Ihren Code zu suchen Users, insbesondere wenn Sie das Manager-Objekt weitergeben. this.users = new Users()Aber dann wird immer irgendwo anders in Ihrem Code usersauf ein Array von Users verwiesen.
Schneemann

Wie Sie sagen, impliziert Benutzer in der Tat eine "Sammlung von Benutzern" - eine Sammlung von Entitäten, die statusbehaftet ist. SRP würde jedoch bedeuten, dass Sie die Benutzerverwaltung (Funktionalität und Geschäftslogik) nicht mit Benutzerdaten (Status) bündeln möchten. Das heißt nicht, dass Sie sich irren, nur dass UserManager geeignet ist, wenn die Klasse für die Verwaltung der Benutzer verantwortlich ist und nicht nur deren Status und grundlegende CRUD speichert.
Richard Moore

5

Speziell für C # fand ich "Richtlinien für das Framework-Design: Konventionen, Redewendungen und Muster für wiederverwendbare .NET-Bibliotheken" viele gute Informationen zur Logik der Benennung enthalten.

Um diese spezifischeren Wörter zu finden, verwende ich oft einen Thesaurus und springe durch verwandte Wörter, um zu versuchen, ein gutes zu finden. Ich versuche jedoch, nicht zu viel Zeit damit zu verbringen, während ich mich durch die Entwicklung entwickle, finde ich bessere Namen oder merke manchmal, dass dies SuchAndSuchManagerwirklich in mehrere Klassen unterteilt werden sollte, und dann wird der Name dieser veralteten Klasse kein Problem mehr .


3

Ich glaube, das Entscheidende dabei ist, innerhalb der Sichtbarkeit Ihres Codes konsistent zu sein, dh solange jeder, der Ihren Code betrachten / bearbeiten muss, Ihre Namenskonvention versteht, sollte dies in Ordnung sein, selbst wenn Sie sich entscheiden, sie aufzurufen 'CompanyThingamabob' und 'UserDoohickey'. Wenn Sie für ein Unternehmen arbeiten, müssen Sie zunächst prüfen, ob es eine Unternehmenskonvention für die Benennung gibt. Wenn dies nicht der Fall ist oder Sie nicht für ein Unternehmen arbeiten, erstellen Sie Ihre eigenen Begriffe mit für Sie sinnvollen Begriffen, geben Sie sie an einige vertrauenswürdige Kollegen / Freunde weiter, die zumindest beiläufig codieren, und berücksichtigen Sie alle sinnvollen Rückmeldungen.

Es ist ein kleiner Fehler in meinem Buch, die Konvention eines anderen anzuwenden, auch wenn sie allgemein akzeptiert wird, wenn sie nicht von der Seite springt. In erster Linie muss ich meinen Code verstehen, ohne auf andere Dokumentationen zu verweisen, aber gleichzeitig muss er so allgemein sein, dass er für andere Personen auf demselben Gebiet in derselben Branche nicht unverständlich ist.


1
Dennoch ist eine konsistente, wenn auch etwas unintuitive Konvention besser, als nur eine eigene Konvention zu starten. Leute, die an einem Projekt arbeiten, werden jede konsistente Konvention sehr schnell lernen und schnell vergessen, dass die Funktionalität nicht ganz das ist, was auf den ersten Blick zu erwarten ist.
Mr. Boy

@ John, genau das habe ich gesagt. Die Konvention muss von der Gruppe akzeptiert werden. Wenn Sie in einem Unternehmen arbeiten, prüfen Sie, ob es eine Firmenkonvention gibt. Für Unternehmen denke ich an jede Gruppe, sei es ein Open-Source-Projektteam oder eine lose Sammlung von Programmierern. Wenn jeder nur das nehmen würde, was verfügbar ist und fast seinen Anforderungen entspricht, dann würde es uns meiner Meinung nach schmerzlich an Innovation mangeln.
Lazarus

2

Ich würde die Muster berücksichtigen, die Sie für Ihr System verwenden, und die Namenskonventionen / Katalogisierung / Gruppierung von Klassen von Tendenzen werden durch das verwendete Muster definiert. Persönlich halte ich mich an diese Namenskonventionen, da sie die wahrscheinlichste Möglichkeit für eine andere Person sind, meinen Code aufzunehmen und damit auszuführen.

Zum Beispiel könnte UserRecordsClerk besser als Erweiterung einer generischen RecordsClerk-Schnittstelle erklärt werden, die sowohl UserRecordsClerk als auch CompanyRecordsClerk implementieren und sich dann darauf spezialisieren. Dies bedeutet, dass man sich die Methoden in der Schnittstelle ansehen kann, um zu sehen, wofür die Unterklassen im Allgemeinen funktionieren.

Siehe ein Buch wie Design Patterns Informationen finden Sie in . Es ist ein ausgezeichnetes Buch und kann Ihnen dabei helfen, zu klären, wo Sie mit Ihrem Code arbeiten möchten - wenn Sie ihn nicht bereits verwenden! ;Ö)

Ich denke, solange Ihr Muster gut ausgewählt und soweit angemessen verwendet wird, sollten ziemlich nicht erfinderische, einfache Klassennamen ausreichen!


Ich habe das zu Brian Agnews Antwort kommentiert. Ich glaube nicht, dass die Musternamen nur in einigen Fällen (Factory, Strategy) gute Klassennamen sind, in anderen nicht (Singleton). Ich möchte, dass die Namen den Job der Klasse widerspiegeln und nicht die Art und Weise, wie ich ihn implementiert habe.
froh42
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.