Ist besser Show () + Hide () oder SetVisible (Bool sichtbar)?


59

Was ist besser und warum? (Aus Sicht des Interface-Designs):

a) Zwei Show()und Hide()Funktionen haben

b) Eine SetVisible(bool visible)Funktion haben

BEARBEITEN: Zum Beispiel haben einige Objekte einen Sichtbarkeitsstatus und diese Funktion wird verwendet, um diesen zu ändern.

c) haben alle drei Show(), Hide(), SetVisible(bool visible)Funktionen


4
In welchem ​​Zusammenhang? Im Allgemeinen spielt es keine Rolle
Aviv Cohn


6
Warum sie nicht alle öffentlich haben? Es gibt Fälle, in denen Sie wissen, dass sie immer angezeigt oder ausgeblendet werden, und es gibt Fälle, in denen Sie bedingt anzeigen oder ausblenden möchten.
Pllee

@pllee: Das ist wahrscheinlich ein sehr guter Punkt.
user3123061

4
In Java wäre es setVisible, hide und show ohne den beginnenden Großbuchstaben.
Pierre Arlaud

Antworten:


81

Ich bevorzuge SetVisible(bool visible), weil ich so Client-Code schreiben kann:

SetVisible(DetermineIfItShouldBeVisible());

anstatt schreiben zu müssen

if (DetermineIfItShouldBeVisible()) {
    Show();
} else {
    Hide();
}

Der SetVisibleAnsatz kann auch eine einfachere Implementierung ermöglichen. Wenn beispielsweise eine bestimmte konkrete Klasse die Methode einfach an ihre zusammengesetzten Klassen delegiert, SetVisiblebedeutet dies, dass eine Methode weniger implementiert werden muss.

void ButtonWithALabel::SetVisible(bool visible) {
    myButton.SetVisible(visible);
    myLabel.SetVisible(visible);
}

25
Ebenso können Sie Visible auch zu einer Eigenschaft machen, sofern Ihre Sprache dies unterstützt. MyObject.Visible = false;Ich finde es sogar noch intuitiver alsMyObject.SetVisible(false);
Brian

9
@Brian Für mich ist es weniger les- und debuggbar, weil es das Programmverhalten für meine Augen verbirgt - den zugrunde liegenden Methodenaufruf -, aber das ist eine andere Geschichte. Java unterstützt diese Syntax nicht, es ist jedoch eine Frage der Präferenz und des Augentrainings.
ignis

10
SetVisible()deutet (für mich) nicht an, dass Sie tatsächlich etwas anzeigen. Es sieht eher so aus, als würden Sie die Sichtbarkeitseigenschaft eines Objekts festlegen und es möglicherweise einer entsprechenden Methode Refresh()oder einem entsprechenden Redisplay()Verfahren überlassen , den Wert dieser Eigenschaft zu überprüfen, um festzustellen, ob das Objekt angezeigt oder ausgeblendet werden soll.
TMN

1
Leider unterstützt Java keine Eigenschaften wie C #, sondern nur die oben gezeigten Getter und Setter.
theGreenCabbage

1
@TMN: Ich würde erwarten, dass in Abwesenheit anderer Faktoren, die die Sichtbarkeit verhindern (Z-Reihenfolge, Sichtbarkeit der Eltern, Standort usw.) setVisible(true), ein Prozess in Gang gesetzt wird, bei dem das Objekt gezeichnet wird, wenn das System das nächste Mal im Leerlauf ist, wenn nicht vorher. Ich würde erwarten, dass refreshdies nützlich sein könnte, um die Anzeige des Objekts zu beschleunigen, aber dass das Objekt letztendlich trotzdem gezeichnet wird (es sei denn, dass z. B. seine Sichtbarkeit falsezuvor eingestellt wurde).
Supercat

35

Ich bin nicht einverstanden mit allen Postern, die mehrere Funktionen vorschlagen, um dasselbe zu tun, ist eine gute Sache. Während drei Funktionen anstelle eines vielleicht nicht viel aufblasen scheinen, denken Sie daran , dass Ihre Klasse wahrscheinlich mit vielen solcher Funktionen , um am Ende (zB setEnabled, enable, disable) und damit dieser Ansatz wird mit einem am Ende viel größeren Klasse - Schnittstelle. Darüber hinaus ist es wahrscheinlich, dass Sie am Ende eine Reihe von ähnlich klingenden Funktionen / Eigenschaften / was auch immer in Ihrer Klasse haben, und die Multiplikation von Funktionen wird weiter verdecken, welche zu was gehört.

In Sprachen, die Eigenschaften unterstützen, sollten diese bevorzugt werden. Da dies jedoch weder in Java noch in C ++ der Fall ist, ist dies vermutlich ein strittiger Punkt.

Ich denke, setVisible()sollte aus folgenden Gründen bevorzugt werden:

  1. Es ist sofort klar, was die Umkehrfunktion ist. Umzukehren setVisible(false)nennt man setVisible(true)hingegen das Gegenteil von hide()könnte leicht sein reveal().
  2. Es ist programmgesteuert einfacher, wenn Sie festlegen, welchen Status der Code annehmen soll, dh Sie können setVisible(wantToSee)eine ifAnweisung aufrufen, anstatt sie zu verwenden .
  3. Sobald Sie mehrere ähnliche Funktionen haben, wird das setX()Format verallgemeinert, sodass Sie eine Reihe von konsistenten Funktionen haben können, während der verbale Ansatz eine Vielzahl von Funktionen hervorbringt, die möglicherweise schwer zu finden sind, wenn Sie nicht wissen, wonach Sie suchen. Die Konsistenz der APIs erleichtert das Lernen und Merken erheblich.

3
C ++ hat keine Eigenschaften, aber es hat freie Funktionen, sodass Sie die Klassenschnittstelle erweitern können, ohne neue Memberfunktionen hinzuzufügen, dh mit einem geringeren Kopplungsgrad.
Phresnel

Qt stellt häufig alle drei zur Verfügung, damit hide () und show () über das Signal / Slot-System direkt mit anderen Ereignissen verbunden werden können. Dies ist jedoch eine echte Einschränkung des Slot-Systems - wenn es etwas ähnlicheres wie boost :: functions verwendet, könnte das true / false-Argument an den Punkt gebunden werden, an dem der Callback eingerichtet wird.

1
"In Sprachen, die Eigenschaften unterstützen, sollten diese bevorzugt werden, aber da weder Java noch C ++ dies tun, denke ich, ist das ein strittiger Punkt." nicht unbedingt. Bevorzugung von Gettern / Setzern? Ja. Aber set_visible ist eigentlich kein Setter.
Miles Rout

19

Es hängt davon ab , welche Ein- und Ausblenden bedeutet im Kontext. Zuerst möchten Sie herausfinden, welches Ihr "Hauptweg" ist, und sich darauf konzentrieren, Folgendes zu entwickeln:

  • Gründe für die Wahl setVisible(bool)
    • Es ist nur ein einfacher Bit-Flip, oder Ihr Objekt befindet sich hauptsächlich im Haltezustand
    • Ihr Objekt wird die meiste Zeit in einem CRUD-Framework verbringen
    • Zwischen dem Ein- und Ausblenden gibt es eine Menge einfach zu teilenden Codes
  • Gründe zu wählen show()undhide()
    • Es werden wichtige Nebeneffekte oder viel Logik ausgeführt, z. B. wenn das Objekt alle Container auf ihren Sichtbarkeitsstatus überprüfen muss oder eine Übergangsanimation auslöst.
    • Ist es Teil eines Domain-Modells, bei dem das Ausdrücken von Absichten wichtig ist?

OK, jetzt, da Sie den "Goldstandard" -Kern codiert haben, müssen Sie herausfinden, ob es sich lohnt, dünne Convenience-Methoden in den anderen Stil einzufügen, um das Leben für jeden zu erleichtern, der Ihr Objekt verwenden möchte.

  • Bequemlichkeit von setVisible(bool)
    • Ermöglicht das Vermeiden von if-Anweisungen, die triviale Bedingungen haben und nur die Sichtbarkeit beeinflussen (z. B. setVisible(a==b))
    • Kann in bestimmte Get- / Setter-Frameworks eingebunden werden, wenn dies zu erwarten ist
  • Bequemlichkeit von show()undhide()
    • Nützlich in einer Sprache mit erstklassigen Funktionen und Rückrufen (z. B. onSuccess(widget.show))
    • Viel einfacher zu lesen mit Stack-Traces und Leistungsprofilen, da Sie schnell sehen können, was das Programm versucht hat

TLDR: Finden Sie heraus, welches das wichtigste ist, implementieren Sie es und fragen Sie sich, ob es sich lohnt, den anderen Stil als Thin-Convenience-Methode hinzuzufügen.


11

Ich würde "alle drei" sagen.

Show()und Hide()sind in der Regel leichter zu fassen als SetVisible(true)und SetVisible(false). Wenn Sie die Sichtbarkeit jedoch logisch festlegen möchten, ist es besser, eine Methode zu verwenden, die eine boolannimmt, als eine ifum diese herum zu konstruieren bool.

Sie können alle drei unterstützen, ohne Logik und minimale Boilerplate zu duplizieren:

void Show() {
    foo.Show();
    bar.Show();
}

void Hide() {
    foo.Hide();
    bar.Hide();
}

void SetVisible(bool visible) {
    if (visible) {
        Show();
    } else {
        Hide();
    }
}

Alternativ, wenn die Dinge, die Sie verpacken, eine mehr SetVisible-ish API haben:

void Show() {
    SetVisible(true);
}

void Hide() {
    SetVisible(false);
}

void SetVisible(bool visible) {
    foo.SetVisible(visible);
    bar.SetVisible(visible);
}

40
Microsoft verwendet diesen Ansatz zum Starten und Beenden System.Windows.Forms.Timer. Persönlich finde ich das verwirrend. Wenn ich beide Showund sehe SetVisible, ist meine erste Neigung, mich zu fragen, ob es einen wichtigen Unterschied zwischen den beiden Funktionen gibt.
Brian

1
Sie können sie leicht dokumentieren, um diese Verwirrung zu beseitigen. Ich tat es nicht, da dies ein einfaches Beispiel war.
Garry Shutler

20
Also muss ich jetzt X zusätzliche Minuten damit verbringen, die Dokumentation zu lesen, bevor ich mich in der Klasse wohl fühle? Oder muss ich alternativ X zusätzliche Minuten damit verschwenden, verwirrt zu sein (oder Fehler einzuführen)? Sicher, X ist für so etwas ziemlich klein, aber es ist definitiv nicht Null. Das Anbieten aller drei Optionen bedeutet, dass Sie dreimal so viele Funktionen wie nötig anbieten, was bedeutet, dass Sie mehr Zeit für das Dokumentieren aufwenden und mehr Zeit für das Erlernen der Verwendung der Klasse aufwenden. Außerdem wird eine weitere Möglichkeit für verschiedene Entwickler eingeführt, inkonsistent zu sein, wenn Sie Ihre Klasse verwenden.
Brian

5
Dies ist ein klarer Verstoß gegen das Prinzip der Schnittstellentrennung, eines der SOLID-Prinzipien. Eine andere Meinung gegen Ihren Ansatz ist die von Jaroslav Tulach, Designer von Netbeans, der oft darauf besteht, nur eine Möglichkeit zu bieten, eine Sache innerhalb einer API in seinem Buch für das praktische API-Design zu tun.
AlfredoCasado

@ AlfredoCasado Ich stimme zu. Was wäre, wenn SetVisible geschützt wäre? Sie könnten von einer Unterklasse aus darauf zugreifen, aber der Aufruf einer bestimmten Entität mit dieser Schnittstelle (z. B. einer API) muss Hide / Show lauten.
Pierre Arlaud

5

Ich bevorzuge show () und hide (). Tatsächlich kann jede Methode, die einen Booleschen Wert erhält, durch zwei Methoden geändert werden, um die Absicht der API besser auszudrücken. Zum Beispiel empfiehlt Robert Martin in sauberem Code, Methoden mit null Argumenten gegenüber Methoden mit einem Argument vorzuziehen.

Ein weiteres wichtiges Argument für mich ist die Lesbarkeit. Meiner Meinung nach kann guter Code wie Prosa gelesen werden. Seine wirklich seltsame Prosa ist etwa "main_window setVisible false" anstelle von "main_window hide". Sie schreiben oder sprechen normalerweise so. Warum verwenden Sie dieses seltsame Argument? Sprachkonstruktion in Softwareprogrammen Wann ist es durchaus möglich, eine natürlichere Sprache zu verwenden?


1
Ist Assembler-Prosa nicht genug?
Alexander

Ich würde erwarten, dass die Sequenz it.setVisible(false); it.setVisible(true);weder die Sichtbarkeit eines übergeordneten Steuerelements noch die Z-Reihenfolge oder Position des Steuerelements beeinflusst. Im Gegensatz dazu hide(); show(); Sie können das übergeordnete Element eines Steuerelements plausibel dazu zwingen, sichtbar zu sein, es über andere Steuerelemente zu verschieben und seine Position auf einen sichtbaren Ort zu beschränken. In einigen Fällen ist es nützlich, ein Mittel zu haben, um sicherzustellen, dass etwas tatsächlich sichtbar ist (wie bei den oben genannten show(), aber in anderen Fällen ist es nützlich, die Sichtbarkeitsflagge zu ändern, ohne etwas anderes zu ändern .
Supercat

In einer objektorientierten API gibt es keine "Flags". Bei OO geht es um Messaging. Es geht darum, anderen Objekten zu sagen, dass sie eine Aufgabe ausführen sollen, und nicht darum, "Flags" zu ändern, die den Status des Objekts haben. Sie machen viele Annahmen über Steuerelemente, Eltern, Z-Reihenfolge und die Dinge, die SIE aufgrund Ihrer bisherigen Erfahrungen mit anderen APIs erwarten. Es ist eine sehr schlechte Idee, eine API auf der Grundlage persönlicher Gefühle und Annahmen zu einer Domain zu entwerfen.
AlfredoCasado

5

Ich glaube, je aussagekräftiger die Methode ist, desto lesbarer und folglich wartbarer wird der Code sein. Betrachten Sie die folgenden zwei Fälle:

Fall 1:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  customerPanel.setVisible(customer.isCustomerEnabled());
}

Fall 2:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  //always show customer panel
  customerPanel.setVisible(true);
}

Im ersten Fall ist klar, was die Funktion "setVisible" tut, aber wenn Sie es lesen möchten, würden Sie sagen:

Setzen Sie das Kundenbedienfeld auf sichtbar, wenn der Kunde aktiviert ist, oder auf ausgeblendet, wenn der Kunde deaktiviert ist.

Während es aussagekräftiger ist zu sagen:

  • Überprüfen Sie den Status des Kunden:
    • Wenn der Kunde aktiviert ist, wird das Kundenfenster angezeigt
    • ansonsten verstecke es

Dadurch wird die Funktion "Fall 1" folgendermaßen geändert:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  if(customer.isCustomerEnabled()){
    customerPanel.Show();
  }
  else{
    customerPanel.Hide();
  }
}

Es erzeugt mehr Code, ist aber besser lesbar.

Der zweite Fall hat einen offensichtlichen Fehler: Sie wissen bereits, dass Sie das Panel anzeigen möchten. Warum also nicht die Funktion "Anzeigen" verwenden?

Ich sage nicht, dass die Verwendung von "setVisible" absolut falsch ist, aber es wird verwirrend, wenn Sie versuchen, Code zu lesen, den Sie im Laufe der Zeit nicht geschrieben haben, und er entspricht nicht der Regel "Eine Funktion sollte nur eine Operation ausführen".


Ich würde sagen: show customer panel iff the user/customer is enabled. Ich stimme zu, dass es viele komplexere Bedingungen geben könnte, die nicht so einfach zu lesen sind wie Ihr Beispiel. In diesen Fällen würde ich diese Bedingungen jedoch in verschiedene Zeilen aufteilen.
ComFreek

5

Ich glaube, dass die Hide()/ Show()alternative attraktiv ist, weil es einfacher ist zu verstehen, was los ist, als mit SetVisible(true), während eine einzelne Funktion vorzuziehen ist, weil es viele Bedingungen vermeidet.

Wenn das der Fall ist, schlage ich vor, eine Aufzählung als Eingabe zu verwenden SetVisible, damit Sie entweder SetVisible(Visibility.Visible)oder erhalten SetVisible(Visibility.Hidden). Sie haben eine einzelne Funktion, mit der Sie sofort ablesen können, welche Aktion ausgeführt wird.

Mit Javas Namenskonventionen hätten Sie vielleicht setVisible(Visibility.VISIBLE)oder setVisible(Visibility.HIDDEN).


3

Ich stimme Dariens Antwort zu, wollte aber einen Standpunkt aus der Perspektive eines C # -Programmierers hinzufügen.

Wenn ich Code sehe, der 'setXXX' sagt, habe ich gelesen, dass es einen Wert für ein Objekt festlegt. Ich erwarte jedoch keine anderen Nebenwirkungen als das Festlegen dieses Werts, und ich erwarte, dass dies idempotent ist (dh ich kann es mit dem gleichen Wert einstellen und es ist in Ordnung). Es ist eher so, als würde man auf ein Feld zugreifen. Im Allgemeinen würde ich auch eine 'getXXX'-Methode zusammen mit einer' setXXX'-Methode erwarten.

Ich weiß nicht, ob dies das ist, was Sie in Java und C ++ erwarten, aber das ist, was ich in C # erwarten würde, obwohl es in C # eine Kurzform für diese Eigenschaft gibt, die Properties heißt. Und hier finden Sie einige nützliche Anleitungen zur Verwendung von Eigenschaften ( http://msdn.microsoft.com/en-us/library/ms182181.aspx ).

In Anbetracht dieser Ansicht hängt die von mir gewählte Benutzeroberfläche nur davon ab, ob es Nebenwirkungen gibt (außer dem Ändern dieses Feldwerts):

Wenn das Ausführen der Aktion Nebenwirkungen hat, z. B. ein Dialogfeld angezeigt wird, würde ich mit "Show ()" und "Hide ()" fortfahren.

Wenn es keine Nebenwirkungen hat, sagen wir, ich stelle die Sichtbarkeit eines "Widgets" ein und etwas anderes rendert das Widget abhängig von seinem Status, dann würde ich setVisibility oder setIsVisible verwenden. (Ich würde es nicht SetVisible nennen).

In C # (bei Java nicht sicher) wird häufig ein Beobachtermuster verwendet, bei dem ein UI-Framework auf Änderungen an Objekten wartet und die Benutzeroberfläche automatisch neu rendert, wenn sich eine Eigenschaft wie Visibility ändert. Das bedeutet, dass das Setzen des Werts durch Aufrufen von setIsVisible so aussieht, als hätte es Nebenwirkungen, in meiner Definition jedoch nicht. Der Vertrag des Widgets wird erfüllt, indem der Feldwert auf "IsVisible" gesetzt wird.

Anders ausgedrückt ist es in Ordnung, die Sichtbarkeit einer Beschriftung in einem Formular zu ändern, bevor das Formular angezeigt wird. Dh label.getIsVisible == true, aber das Formular wird nicht angezeigt.

Es ist nicht in Ordnung, Hide () aufzurufen, wenn das Formular nicht angezeigt wird.


1
Ihre Beschreibung von getXXX()und setXXX()Methoden als Möglichkeit, auf ein Feld ohne Nebenwirkungen zuzugreifen, klingt nach Java und nicht nach C #. Dies ist die Art und Weise, wie Sie es in Java tun müssen , da es keine Eigenschaften hat. Wenn ich solchen Code in C # sehen würde, würde ich vermuten, dass er von einem Java-Entwickler geschrieben wurde, der noch nichts über Eigenschaften in C # gelernt hatte.
gilly3

+1 für SetVisibility.
Altar

@ gilly3 - Ja natürlich. Und "Eigenschaften" sind in der CLR nicht vorhanden. C # übersetzt in Methodenaufrufe get_XXX und set_YYY in IL. Mein Punkt ist: im Kontext der Frage, wenn Sie setXXX, getXXX in Java sahen, würden Sie erwarten, dass es mit der gleichen Semantik wie Eigenschaften in C # funktioniert. Wenn das stimmt, dann denke ich, dass die gleichen Richtlinien für Eigenschaften in C # für Paare von setXXX und getXXX in Java gelten. Ich stimme den Richtlinien zu, auf die ich in diesem Beitrag verweise, und empfehle daher dieselben Richtlinien für die Verwendung in diesem Szenario in Java beim Definieren der Schnittstelle.
Daniel James Bryars

1
Es kann hilfreich sein, zu verdeutlichen, dass Sie mit "Nebenwirkungen" "andere als die" beobachtbaren "Dinge" meinen. Die Regel, die ich favorisiere, lautet: Wenn ein getXXAufruf eine entsprechende setXXMethode hat, setYYsollte dies keine Auswirkungen haben, aber es kann sich auf einen getZZAufruf auswirken , der keine setZZMethode hat.
Supercat

2

Ich würde ein leicht modifiziertes Interface vorschlagen:

Show();
Hide();
ToggleVisible();
ToggleVisible(bool visible);

Bessere Namen

Diese Methodennamen helfen dem Entwickler bei der Entscheidung, welche Methode basierend auf den durchzuführenden Schritten verwendet werden soll. Während SetVisible(bool visible)ein Entwickler verwirren kann, weil er die gleiche semantische Bedeutung wie Show()und vermittelt Hide(), Toggle()impliziert dies die Existenz einer Bedingung, die die Aktion bestimmt. Für den Entwickler wird es somit intuitiv, wann jede Methode anzuwenden ist.

Reduzierte Code-Redundanz

Der Vorteil der Verwendung mehrerer Methoden in Ihrer Schnittstelle besteht darin, dass der aufrufende Code vereinfacht wird. Sie könnten nur Show()und aussetzen Hide(), aber:

  • Sie würden wahrscheinlich eine SetVisible()private Methode benötigen, um die eigentliche Arbeit hinter den Kulissen zu erledigen (oder redundanten Code für Show()und zu schreiben Hide()).
  • Der aufrufende Code enthält möglicherweise viele redundante if / else-Blöcke, um die zu verwendende Methode auszuwählen. Das bläht meiner Meinung nach den Code auf.
  • Wenn ich der Verbraucher wäre, würde ich wahrscheinlich nur meine eigene Wrapper-Funktion schreiben, die das tut, was SetVisible()(oder Toggle()) bereits tut, um ein Aufblähen des Codes zu vermeiden (ich hasse redundanten Code). So duplizieren Sie eine Methode, die wahrscheinlich bereits als private Methode in der Implementierung vorhanden ist.

1
Die Methodenvervielfältigung klingt vernünftig, obwohl ich es selbst nicht tun würde. Andererseits stimme ich nicht zu, dass toggleVisible (bool) intuitiv ist. Für mich bedeutet das, dass man umschalten sollte, ob der übergebene Bool wahr ist, was ziemlich seltsam wäre, aber ich habe Fremde gesehen. Es würde nicht davon ausgehen, dass es sich wirklich um eine festgelegte Funktion handelt.
Patrick M

0

Ich würde nur empfehlen, SetVisible(bool)wenn die Sichtbarkeit zweimal umgeschaltet wird (Anzeigen und erneutes Ausblenden oder Verbergen und erneutes Anzeigen), die Dinge im Wesentlichen im gleichen Zustand wie vor der Durchführung der Operation zu belassen (in Ordnung, wenn Anzeigen und erneutes Ausblenden) etwas oder umgekehrt hinterlässt Objekte, die neu gezeichnet werden müssen, vorausgesetzt, es kann damit gerechnet werden, dass dies "automatisch" geschieht. Wenn das Ausblenden und Anzeigen eines Objekts keine anderen Auswirkungen hat als das Ändern eines Statusbits, ist es für externen Code sinnvoll, über Methoden zu verfügen, die einen Sichtbarkeitsparameter akzeptieren, und das Schreiben eines solchen Codes wird durch erleichtert SetVisible.

Wenn das Ausblenden und Wiedereinblenden eines Objekts Nebenwirkungen haben kann, z. B. das Ändern der Z-Reihenfolge, sollten solche Aktionen mit größerer Wahrscheinlichkeit mit separaten Methoden ausgeführt werden. In solchen Fällen ist die Nützlichkeit von externen Methoden, die einen "Sichtbarkeit" -Parameter akzeptieren, begrenzt, und daher ist es wenig vorteilhaft, sie zu vereinfachen. Ferner wird eine SetVisibleMethode (fälschlicherweise) vorschlagen, dass Änderungen an der Sichtbarkeit von Objekten ohne Nebenwirkungen durchgeführt werden können.

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.