C# Getter + Setter, Public vs. Private: (Schwach)sinn?

H

Housechen

Gast
Hi
Also es ist zwar mehr ein theoretisches "Problem", aber ich habe mal C# als Sprach-Präfix gewählt, weil ich diese in der Regel benutze.

Folgender Diskussionspunkt:
Mein Lehrer besteht immer darauf alles private zu setzen mit Gettern UND Settern, die dann auch nur return foo; bzw. this.foo=foo; enthalten.

Ich persönlich setze gerne Public und spare mir das Ganze, solange keine der Kriterien erfüllt sind:
-Variablen sollten readonly sein (Dazu gibt es glaube ich auch so ein "Attribut" oder wie auch immer man das nennt, aber davon jetzt mal abgesehen), in diesem Fall dann nur den Getter anlegen.
-Es müssen bestimmte Umwandlungen oder andere Aktionen daran gebunden werden, Beispiel:
Klasse Auto mit int MaxGeschwindigkeit, die dann als km/h behandelt werden in den einzelnen klasseninternen Funktionen und Methoden. Dazu dann die Methode setMaxGeschwindigkeit, die als Parameter zum Beispiel m/s als Einheit erwartet oder durch andere Berechnungen mit Hilfe der Parameter und die Geschwindigkeit in km/h kommt. Dementsprechend hier im Beispiel evtl. auch eine entsprechende Get-Funktion.

Woher diese Problematik?
Ich habe im Rahmen meiner Facharbeit mein Projekt halt in "meinem Stil" geschrieben (Habe auch nur Public deklariert, wenn es nötig war). Aufgrund der oben aufgeführten Argumente finde ich die Lösung meines Lehrers schwachsinning, möchte meine Entscheidung aber auch gerne mit fundiertem Fachwissen begründen.


Naja jetzt kommt hoffentlich eure Meinung und Hilfe dazu ins Spiel.
"Auf´s fröhliche Diskutieren!" :D

Vielen Dank im Voraus und mfg
Cyba_Mephisto
 
Es zeugt halt von schlechten Stil wenn man sich nicht dran hält, entweder ganz (=gut) oder garnicht (=schlecht).
 
Es ist halt schöner, den Computer mit dem Power-Button zu starten, als durch die offene Seitenwand mit nem Schraubenzieher die PWR-Pins zu brücken. Stichwort "Kapselung". :D
 
Hi, also Getter und Setter werden eingesetzt, wenn die Klasse diese Werte als Properties (Eigenschaft) bekommt. Man nutzt sie in der Regel um Werte aus der Klasse raus zu geben, oder um sie als Datenhalter zu nutzen (dann aber leere get; und leere set;.

Ein Beispiel:
Code:
public string Name { get; set; }

Nun zu der Frage, public oder doch private...

Also als erstes, Getter und Setter werden zwecks guten Stils immer mit deklariert.
Braucht man den setter nicht, weil der getter einen festen Wert geben soll, dann wird der setter privat gesetzt:

Code:
public string Name { get; private set; }

Somit ist es dann auch nur möglich den Wert von innerhalb der Klasse zu setzen und man erreicht schon mal eine gute Kapselung, denn das ist ja Ziel der Getter und Setter (Properties).

Das gleiche Spiel geht auch umgedreht, also getter private, weil man einen Wert in die Klasse geben möchte nach dem sie initialisiert wurde, also nach dem Constructor aufruf.

Code:
public string Name { private get; set; }

Hat man nun den fall, das man gar keinen Wert von außen haben oder nach außen geben möchte, brauch man auch keine Properties. Dann reichen private deklarierte Variabeln absolut, sofern es überhaupt notwendig ist.


So richtig steig eich durch deinen Text nicht durch mit der Geschwindigkeit etc.
Aber genau da kann das angewandt werden was ich oben beschrieben habe. Diese Umrechnungen von m/s -> km/h können im setter passieren. Somit wird m/s gegeben und man kann intern sofort von der Propertie mit km/h arbeiten. Natürlich geht das auch beim getter. Dann wird der Wert erst bei der Rückgabe umgerechnet.


omfg, ich hoffe man versteht was ich sagen will... :freak:
 
Wenn ich ein Quelltext bekomme in einer objektorientierten Sprache und alles ist als Public deklariert, muss ich davon ausegehen das der Autor des Quelltextes OOP nicht verstanden hat, eben genau die Möglichkeit des Informationhiding.

Dieses Problem was du da beschreibst ist aber ein typisches. Ich meine eine Klasse muss ja nicht alles Preisgeben was sie besitzt. Zudem muss man auch in den gettern und settern aufpassen was mit referenzen passiert (sprich in c# ref), nicht das du da ungewollte Seiteneffekte hast. Insofern macht es schon Sinn getter und setter zu verwenden...

c++ bietet für spezielle Klassenabhängigkeiten auch das schlüsselwort "friend" bin schon zu lange aus c# draußen, vllt gibt es das auch.

Gruß
 
Also erstmal danke für alle Antworten!

HaGGi.13 schrieb:
Aber genau da kann das angewandt werden was ich oben beschrieben habe. Diese Umrechnungen von m/s -> km/h können im setter passieren. Somit wird m/s gegeben und man kann intern sofort von der Propertie mit km/h arbeiten. Natürlich geht das auch beim getter. Dann wird der Wert erst bei der Rückgabe umgerechnet.

Ja das meinte ich eigentlich auch, nur verstehe ich den Zweck von Gettern UND Settern in Kombination mit private bei der Variablendeklaration nicht ganz, jetzt abgesehen von unserem Geschwindigkeitsfall, wo ich Getter und Setter verwenden würde.

Hmmja..."Kapselung". Was bedeutet Kapselung genau und erst recht unter diesem für mich immernoch widersprüchlichem Aspekt?

@methical:
Und wenn "Stil" Sinneinbußungen mit sich trägt ist das auch schonmal kein Argument.
 
Zuletzt bearbeitet:
Was ist Datenkapselung?

... kurz gesagt, gib nur das deiner Klasse preis, was auch sein muss. Ich meine du lässt doch auch nicht deine Wohnungstür und Fenster breit offen stehen im denkeln und dann auch noch Licht an im ganzen Haus während du da drinne nackig umher hüpfst oder? ;) :D

Man setzt sie halt private, wenn man sie nicht von außen sehen soll, sprich man "versteckt" sie vor äußere Zugriffe. Bei public, würden sie ja volle Kanne sichtbar sein, für alles und jeden und das darf bei einem guten OOP Stil nicht sein.
 
Also ich setze auch immer nur das Public, was auch unbedingt sein muss.
Was Datenkapselung an sich ist, ist mir schon klar, nur ist mir gerade unter folgenden Bedingungen keinen Bezug dazu:

Nur habe ich mit private foo und public get/setfoo die gleichen Zugriffsrechte wie public foo ohne Getter und Setter, unter den Voraussetzungen, dass Getter und Setter keine weiteren Befehle ausführen.

Daher rührt jetzt für mich, für diesen Fall, die Sinnfrage.
 
Kapselung heißt das eine andere Klasse von außen nicht sehen kann was in der Klasse geschieht. So kannst du zB die komplette Implementierung der Klasse ändern ohne das die andere Klasse was mitkriegt.

Wo trägt der Stil denn Sinneinbußungen mit sich?
Nach deiner Methode müsste ich also auf Auto aufrufen:

für Max Geschw.:
auto.setMaxKmh(25000) //Hier fänden zB noch Umrechnungen statt von Ms nach h

aber für die Farbe zB.:
auto.farbe(grün) //Jede Farbe darf gesetzt werden

So und jetzt kommt einer daher und kennt sich in deinem Quellcode nicht aus, wüsste gerne auf einen Blick welche Attribute eines Objektes er ändern kann. Geht er jetzt die Klasse durch und muss jedes Feld und jede Methode angucken um zu schauen ob man damit Werte ändern kann?
Oder sagt er einfach objekt.set drückt Strg+Space für codecompletion und hat auf anhieb eine komplette Liste mit allen Methoden mit denen man Attribute des Objekts ändern kann?
Soviel zum Thema Sinneinbußung, du solltest dir echt nochmal das OOP Konzept zu gemüte führen =)
 
Also ich kenne schon Prinzip und Grundlagen der OOP, nur hast du scheinbar meinen Post nicht aufmerksam genug gelesen.

Ich habe dieses Autobeispiel als AUSNAHME genommen, um nicht gleich mal direkt die Contraposition einzunehmen und gewisse Fälle auszugrenzen, wie eben die Karrengeschichte.

Es geht hier um den Sinn bei:

Code:
Klasse Foo

private int blub;

public int getBlub
    return blub;

public void setBlub(int Blub)
    this.blub=blub;

Da Getter und Setter hier in diesem obigen Beispiel sonst keine speziellen Aufgaben erledigen, die notwendig sind, oder der Kapselung auch nur in irgendeiner Form dienen, (nehmen wir mal an, die Klasse wird nichtmehr erweitert, das wäre schon alles) wieso dann nicht auch einfach:

Code:
Klasse Foo

public int blub;
 
Weil Unterklassen evtl nicht auf blub zugreifen dürfen?
Weil irgendwann vllt doch mal blub validiert werden muss?
Willst du dann nur die Methode setBlub anpassen wollen oder die 1000 Stellen in deinem Code finden wo blub geändert wird und dann dort die gleiche Validierung 1000 mal reinschreiben (Stichword Coderedundanz)?
 
1. Kann noch weiter außerhalb abgekapselt werden, wenn es unbedingt sein muss. In meinem Projekt ist dies eh der Fall. (2D-Spiel-Engine)

Zu 2+3: Also bevor ich an die Tastatur gehe plane ich alles gaaaaanz genau durch. Ich tippe praktisch am Ende nur von irgendwelchen Zetteln ab. Insofern schließe ich das jetzt mal aus. Außerdem geht das jetzt an dem Beispiel vorbei, ich sagte ja, dass die Klasse und ihr Einsatz in diesem Beispiel als final betrachtet werden soll. Den Rest kann ich mir ja selber denken, habe das jetzt nicht umsonst explizit erwähnt.
 
Na wenn du so ein toller Planer wünsche ich dir weiterhin viel Erfolg :D
Solltest du irgendwann mal dein Brot mit Programmieren verdienen, frage ich mich ob du den Kunden auch so gut Einschätzen kannst, dass wenn er nach nem Jahr mit ein paar Change Requests ankommt du nicht vllt doch eine zusätzliche Validierung irgendwo einbauen musst. Ich wünsche es dir, vllt begreifst du es ja dann :D
Naja ich klinke mich hier mal aus, macht keinen Sinn hier weiter zu diskutieren.
 
... hmmm... ich finde das ist absolut egal wie gut es geplant ist, es zeugt einfach von einem schlechten programmier Stil und daher stimme ich methical voll und ganz zu.

... bin auch aus der Diskusion raus...
 
Das es direkt so unter den normalen Umständen keinen Sinn macht ist mir schon klar, dass ist aber gerade nur eine theoretische Geschichte, was ich jetzt auch schon oft genug betont habe, es geht mir nur um den technischen Unterschied. Wenn ich dann solche Antworten bekomme, die trotz weiterer Erklärungen keinen direkten Bezug auf die Frage haben und ich dann so ´nen Abgang hier bekomme, kann ich beileibe darauf verzichten.

Wenn ich dann allerdings dann noch so eine Arroganz als Beilage serviert bekomme, sollte man echt die antike Exekutive wiedereinführen und solchen Postern die Finger abhacken.
 
Cyba_Mephisto schrieb:
[...]nur eine theoretische Geschichte[...]

Na ja, so "nur" ist das leider nicht, es ist ein fester Bestandteil der OOP.
Klar ist es kein einfaches Thema, aber es wurde ja nun öfter versucht, wenn auch nicht expliziet auf dein Beispiel bezogen, versucht dir denn eigentlichen Sinn näher zu bringen. Aber irgendwie behaarst du auf deinen Standpunkt ohne Einsicht...
Es ist am Anfang schwer zu verstehen, ging mir ja auch so... ;) Aber an diesem Punkt der Properties und Datenkapselung sollte man es nicht hinterfragen und einfach akzeptieren. Es hat mit Datensicherheit, Validierung und Kapselung zu tun. Und das sind echt wichtige Punkt in der Programmierung, gerade in so einer mächtigen Sprache wie C#.

Objektorientierte Programmierung <- da stehen auch noch mal wichtige Grundsätze drin.
Ich lege es dir echt ans Herz.
Es gibt nichts schlimmeres für einen anderen in einen Quellcode zu gucken vom Vorgänger und dann ein Haufen Ausbesserungsarbeiten zu machen...
Das sind halt nur Erfahrungswerte. ;)
Ich verdiehne damit halt mein Brot und bin immer froh noch was dazu zu lernen...

Also sei nicht sauer... :D
 
So, bevor ich anfange die Borniertheit der anderen zu befluchen:

ICH WEIß, dass es sinnlos ist. Es ging mir nur um den technischen Aspekt, nicht um die Planung, Projektstruktur oder sonstiges. Natürlich sollte man sowas nicht machen.
Wer darüber nicht mal kurz hinwegsehen kann...
 
Naja Meph der technische Aspekt sollte ja klar sein und wurde ja auch oft genug hier angeprangert. Ich verstehe dein Problem und war am anfang auch kein Freund davon. Mittlerweile muss ich allerdings sagen nehm ich die Sache ziemlich ernst, aber erst nach einer einstündigen Diskussion mit meinem damaligen Prof über genau dieses Thema. Letztendlich ist es nichts anderes als ein bewährtes Prinzip bzw. Programmierparadigma das Information Hiding in jeder Klasse möglichst gut umzusetzen. Es erspart spätere Änderungen und macht den Code stellenweise nunmal einfacher lesbar.

Es geht halt hierbei, wie so oft ob eine Methodik die einfach fest verankert ist. Es ist ausserdem eine ungeschriebene Regel klassenintern ebenfalls getter und setter zu verwenden. Aber es gibt eine Schwelle, die absolut kontextabhängig ist, ab der ich sagen würde dass es auf jeden Fall Sinn macht mit Standardzugriffsmethoden zu arbeiten. Was aber in meinen Augen immer Sinn macht ist Information Hiding zu betreiben, alleine schon wegen der nachhaltigen Wartbarkeit vom Code. Letzteres ist aber auch immer im Zusammenhang mit der jeweiligen Größe des Programms zu sehen. Ich habs mir einfach angewöhnt grundsätzlich immer getter und setter zu verwenden und anzulegen, sofern ich sie denn brauche (beispielsweise bei Überprüfungen im setter, oder man denke an das Observer Pattern, und die dabei geschickterweise aktualisiere()-Methode beim neuen Setzen eines Wertes).
 
Wenn ich da auch mal etwas dazu beitrage, dann folgendes am Beispiel einer kleinen Klasse:

Code:
public class FooBar
{
  public string unsave;
  private string save;

  public string Save
  {
    get { return this.save; }
    set { if(value != null) this.save = value;}
  }

  public FooBar()
  {
    this.unsave = string.Empty;
    this.save = string.Empty;
  }

  public void DoSomethingUnsafe()
  {
    if(unsave.Length > 0)
      System.Diagnostics.Debug.WriteLine("Unsave: " + this.unsave);
  }
  public void DoSomethingSafe()
  {
    if(save.Length > 0)
      System.Diagnostics.Debug.WriteLine("Save: " + this.save);
  }
}

Jetzt ergibt sich folgendes für das Feld unsafe deiner Klasse:
1. Jede beliebige Klasse kann direkt auf das Feld unsave schreibend zugreifen und reist damit ein Loch in die Stabilität deiner Klasse. Die Anwender/Programmierer die deine Klasse verwenden, müssen wissen, dass unsave nicht null gesetzt werden darf, weil sonst DoSomethingUnsafe() eine NullReferenceException auslöst.
2. Du hast innerhalb der Klasse einen Overhead an Validierungsprüfungen in jeder(!) Methode deiner Klasse um genau diese Fehlerquelle (NullReferenceException) abzufangen, z.B. müsste DoSomethingUnsafe() vor dem ersten Zugriff auf unsave prüfen ob unsave == null ist
3. Jede beliebige Klasse kann direkt auf das Feld unsave lesend zugreifen und reist damit ein Loch in die Stabilität von sich selbst. Die Anwender/Programmierer die deine Klasse verwenden, müssen wissen, dass unsave null gesetzt sein kann. Sie müssen eine Validierungsprüfung in jede Methode ihrer Klassen einbauen, die unsafe verwendet.
4. Das Schreiben von Unittests um die Klasse auf Robustheit/Stabilität/Verwendbarkeit zu prüfen, ist unmöglich, weil man das Interface deiner Klasse nicht in allen Variationen eines Softwareprojektes testen kann! Ungeprüfte Zweige des restlichen Programmes setzen unsafe auf null und schon hast du eine Exception deren Ursache nicht oder nur schwer und zeitintensiv gefunden werden kann. Bei einem kleinen Programm wäre eine Suche vielleicht noch möglich, bei großen Projekten unmöglich.
5. Optimierungsmaßnahmen deiner Klasse sind nicht möglich, weil du als Programmierer nicht abschätzen kannst, wie deine Klasse von den anderen Anwendern/Programmierern verwendet wird.

Nun aber auch zu den Getter/Setter:
1. Der Setter kann mit 1 Zeile Code um eine Validierung erweitert werden, sodaß bei null-Werten ein Default wie String.Empty gesetzt werden kann.
2. Die Anwender sind sich gewiß, das egal was sie der Property zuweisen (ob null oder ein realer String), die DoSomethingSafe() Methode würde dennoch funktionieren und keine NullReferenceException auslösen.
3. DoSomethingSafe() hat keinen Overhead bzgl. (save == null), weil die Prüfung ja bereits im Setter gemacht wird und somit stets ein gültiger String drin steht.
4. Das Schreiben von Unittests ist relativ einfach, weil hier recht wenige Dinge geprüft werden müssen:
Code:
FooBar foobar = new FooBar();
foobar.Save = null;
foobar.DoSomethingSave();
// und 
FooBar foobar2 = new FooBar();
foobar2.Save = "Hier ein richtiger String!";
foobar2.DoSomethingSave();
5. Optimierungsmaßnahmen sind ohne Quereffekte auf das restliche Programm möglich, solange das Paradigma innerhalb der Klasse eingehalten wird, dass save immer != null ist.

Das ist eine für mich sehr wichtige - wenn auch nicht vollständige - Liste die u.a. über den Erfolg/Misserfolg eines Softwareprojektes entscheiden.

Für ein selbstgeschriebenes kleines Programm das hoffentlich nicht(!) im Internet oder anderswo der Öffentlichkeit zugängig gemacht wird, ist eine public Variable innerhalb einer Klasse ausreichend, wenn es das ist, was du hören wolltest.

Viel Erfolg!
 
Zuletzt bearbeitet:
Wobei ich im allgemeinen anfügen möchte das Information Hiding keine Erfindung des OOP ist.
Information Hiding geht auch mit einer Sprache wie C und sollte dort ebenfalls angewandt werden.

Zur Frage wo der technische (rein technische) Unterschied ist (so wie er das Beispiel gesetzt hat):
Es gibt keinen. Es macht beides genau dasselbe.
Aber es gehört sich einfach nicht. nicht gestern, Nicht heute, nicht morgen. Wenn du es jetzt noch nicht einsehen magst, irgendwann kommt der Punkt wo du sagst, hätte ich doch.
Mehr Bedarf es nicht an Belehrung, finde ich, denn man mus davon wirklich überzeugt sein.

edit:
in C# z.B. ist das ausprogrammieren von getter, setter nicht länger als ohne, man muss nur 2 mal Tab-ben, der Rets geht von selber fürs erste.
 
Zuletzt bearbeitet: (Stein der Weisen gefunden)
Zurück
Oben