Visual C# 2012 Grundkurs

Kapselung, Separation of Concerns

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Die zwei wichtigsten Konzepte der objektorientierten Programmierung sind die Kapselung und die Separation of Concerns. Dieses Video zeigt die Vorteile dieser Konzepte im Detail.

Transkript

In diesem Abschnitt möchte ich zwei grundlegende Konzepte der objekt- orientierten Programmierung vorstellen. Das sind die Kapselung und die Separation of Concerns. Zu dem Zweck möchte ich uns ein bisschen zurückversetzen, in die Zeiten der prozeduralen Programmierung. Also als ich seinerzeit studiert habe, da ist gerade druckfrisch das Buch von Niklaus Wirth erschienen, das da hieß "Algorithmen und Datenstrukturen". So hat man die Programmierungen damals verstanden, man hat tote Datenstrukturen, die einfach irgendwelche Daten aufnehmen können und man hat Algorithmen, die diese Datenstrukturen manipulieren. Und diese Algorithmen hat man zusammengefasst in aufrufbare Einheiten, die sogenannten Prozeduren. Und daher hieß das Ganze auch prozedurale Programmierung. Diese prozedurale Programmierung unterscheidet sich doch erheblich von der objektorientierten Programmierung solcher Sprachen wie eben C#. Für dieses Beispiel möchte ich unser C# Programm einmal so abändern, dass es so aussieht, als würden wir mit einer prozeduralen Programmiersprache arbeiten. Also mache ich jetzt mal Folgendes: Ich lege mal hier so eine Methode an, "void doIt()". In dieser Methode wird gleich ein bisschen was passieren und hier lege ich jetzt mal ein Objekt von der Klasse an und rufe diese Methode "Do It" auf. Jetzt lasse ich das Ganze hier mal verschwinden. Auch hier, diesen Anfang, sodass ich wirklich nur noch meine Prozedur "Do It" da habe. Das soll jetzt die Hauptprozedur meiner Applikation sein. Und jetzt tue ich, was man eben früher getan hat: Ich lege eine Datenstruktur an. In dem Fall möchte ich mit Vektoren arbeiten. Jetzt brauche ich natürlich die Bordmittel von C#, um so einen Vektor anzulegen. Wir nehmen jetzt mal für einen Augenblick an, als ob es sich bei dem Array, das ich hier anlege, auch wirklich nur um die bloße Datenfläche handelt, dass dieses Array ansonsten überhaupt keine Fähigkeiten hat. Also ich habe jetzt hier das Array angelegt. Jetzt kann ich mit diesem Array irgendetwas machen in meiner Hauptprozedur. Fangen wir mal an und füllen das Array mit Werten. Ich fülle das mit dem Wert der Schleifenvariable. D.h. wir haben jetzt ein Datenstruktur. Die Bedeutung dieser Datenstruktur ist die eines Vektors. Ich möchte jetzt eine Skalarmultiplikation ausführen und was ich dafür brauche, ist eine Prozedur, die so etwas kann. So eine Prozedur will ich gerade mal schreiben. Also schreibe ich hier so etwas wie -- Und den Ganzen muss man jetzt einen Vektor übergeben, D.h. einen Integer Array letztendlich und den Wert, mit dem wir multiplizieren wollen. Und jetzt kann ich in dieser Methode -- Schreibe ich jetzt hier meine Schleife und weise ich hier den neuen Wert zu. Damit ist also jetzt dieses Array, jeder Wert von diesem Array mit diesem Wert "Value" multipliziert. Das ist meine Skalarmultiplikation. Diese Prozedur kann ich jetzt aufrufen: "Scalar Multiply Vector, 2. Jetzt habe ich das Ganze mit zwei multipliziert. Jetzt geben wir das Ganze auf der Konsole aus. Dazu brauche ich eine Schleife und ich gebe das Ding jetzt hier einfach mal aus: "Vector von i". Schauen wir mal, ob unser prozedurales Programm funktioniert. Siehe da: Funktioniert. Ursprünglich waren die Werte 0;1 drin, dann wurden sie mit 2 multipliziert, das gibt 0;2. Sehr schön. Jetzt möchte ich an unserem prozeduralen Programm eine kleine Änderung anbringen. Ich stelle fest, dass es nicht ausreicht, mit zwei Dimensionen zu arbeiten, ich muss leider mit drei Dimensionen arbeiten. Also muss der Vektor jetzt hier einfach mal vergrößert werden. Jetzt ist es aber natürlich schon doof. Jetzt muss ich durch das gesamte Programm durch, muss überall da in diesen Schleifen- variablen die Zwei zu einer Drei machen. Sie wissen, wie so etwas ist. Irgendeine Stelle vergisst man immer. Es ist jetzt in dem Fall diese hier. Wenn ich jetzt das Programm aufrufe, das funktioniert natürlich nach wie vor, es lässt sich kompilieren. Es läuft durch. Aber es hat einen fatalen Fehler drin. Hier sollte eigentlich nicht eine Zwei, hier sollte eine Vier stehen. Also ist innerhalb der prozeduralen Welt auch Abhilfe nötig. Diese Abhilfe sieht folgendermaßen aus, indem ich nämlich eine Konstante oder eine Variable oder wie auch immer mit der Länge dieses Vektors initialisiere. Jetzt kann ich in dieser Hauptprozedur diese Variable verwenden. In alle sonstigen Prozeduren kann ich ja diese Länge einfach mit übergeben. Aber Sie sehen schon, dadurch wird jetzt dieser Code und aller anderer Codes, der Vektoren manipulieren können soll ein bisschen unhandlich. Hier kann ich aber dieses length verwenden. Siehe da, wenn ich das jetzt aufrufe, es funktioniert, aber es hat gravierende Nachteile. Nachteil Nummer eins ist, dass ich mich überall in diesem Programm um die Länge dieser Vektoren kümmern muss. Ich muss einfach sehen, wie lang ist dieses Ding? Ich muss diese Länge überall im System herumreichen und dabei darf natürlich nichts passieren. Wenn ich es irgendwo vergesse, gehöre ich der Katz. Und das Zweite ist, dass ich im Grunde genommen an jeder Stelle des Systems diesen Vektor auch wieder abändern kann und dadurch irgendwelche Phänomene erzeugen kann, die ganz tolle Wirkungen entfalten. Wie z.B. hier, dass statt des erwarteten Wertes Vier auf einmal eine Null drin steht. Die Fehlersuche in solchen Systemen ist eine schlichte Katastrophe. Dieser Missstand wird behoben durch objektorientierte Programmierung. Ich versuche also jetzt, aus diesem Vektor eine Klasse zu machen, deren Objekte ich benutzen kann. Deswegen schreibe ich jetzt hier "Class Vector" und schaue mal wie man das Ganze umwandeln kann. Die braucht natürlich auch noch so einen Integer Array, das nenne wir jetzt mal "Values" und es braucht irgendeine Längenangabe. Aber, das Schöne an der Geschichte jetzt ist, dass ich einen Konstruktor schreiben kann, mit dem ich die Länge mal initialisieren kann. Also "Public Vector and Length". Ich brauche nicht mehr fest kodieren, wie lang mein Vektor ist, sondern ich kann es jetzt ganz einfach angeben. Deswegen werfe ich auch hier diese Initialisierung mal raus und kann jetzt sagen "this.length=length" und "this.values=new int(lenght)" und damit habe ich die Sache sauber initialisiert. Das Nächste, was ich tun kann ist, dass ich alle Manipulationen, die ich an so einem Vektor ausführen kann, in diese Klasse hinein verlagere, z.B. dieses "Scalar Multiply" daraus mache ich jetzt eine Methode dieser Klasse. Und schauen Sie mal, was jetzt mit der Parameterliste passiert. Das tut so richtig gut, das alles rauslöschen zu können. Trotzdem ist es die gleiche Funktionalität. Hier kann ich jetzt auch noch diese wunderschöne C# Schreibweise verwenden. Dann wird das Ganze noch besser lesbar. Soweit zu meiner Klasse. Diese Klasse wird noch ein paar Elemente dazu bekommen müssen. Das werden wir jetzt gleich sehen, wenn wir anfangen, mit der Klasse zu arbeiten. Ich muss zunächst einmal ein Objekt von der Klasse anlegen und kann hier die Länge mit angeben. Das ist der einzige Punkt, wo ich mich überhaupt um die Länge dieses Vektors scheren muss und selbst da könnte man noch sagen: Ich mache eine Klasse "3D Vektor" und eine Klasse "2D Vektor". Dann ist die Länge aus dem aufrufenden Kontext komplett heraus. Aber in dem Fall möchte ich das Ganze so flexibel wie möglich halten. Jetzt muss ich den Vektor irgendwie initialisieren. Dazu muss ich in der Lage sein, einzelne Elemente zu manipulieren. Das könnte ich jetzt z.B. über den Konstruktor machen. Das wäre sogar eine relativ gute Idee, oder ich mache eine Setter-Funktion. Das will ich hier mal gerade skizzieren: "Public void setValue (int index,int value)". Jetzt kann ich hier diesem Array irgendeinem Wert zuweisen. Dieses "Set Value" kann ich derweil mal zur Initialisierung meines Vektors verwenden. Was ich dann allerdings auch brauche, das wäre so ein, -- Ja, das ist der Vorläufer des Properties, ein Getter, eine Get-Funktion: "Public int getLength()". Jetzt kann mir der Vektor selber sagen, wie lange er ist. Das kann ich jetzt verwenden, um den Vektor zu initialisieren. Ich habe mich verschrieben. Ich habe das gerade eben mit dem Reflektor-Werkzeug von C# verändert. Und zwar funktioniert das genauso, wie wenn man in Windows irgendetwas umbenennen möchte. Man drückt einfach die F2-Taste und nun kann man irgendetwas angeben hier. Das Fenster, was man zwischendrin gesehen hat, das war dieses Preview-Fenster. Das kann man aber auch ausschalten, diesen Preview. Dann würde man beim Druck auf Return gleich die Änderung im Code haben. Zurück zum Code. Ich initialisiere jetzt hier "vector.setValue(i,i). Damit ist der Vektor initialisiert. Und jetzt kann ich diese unsehnliche Zeile -- Diese Methode muss ich natürlich erst mal Public machen, damit ich sie hier verwenden kann. Und hier kann ich jetzt "Scalar Multiply" aufrufen, einfach unter Angabe des Multiplikanten und schon bin ich mit dem Code hier durch. So etwas geht natürlich überhaupt nicht mehr. Niemand kann mehr unterwegs auf diese Werte zugreifen. Es sei denn, man benutzt diese Set-Value-Funktion. Aber dann hat man jetzt an der Stelle -- Das will ich jetzt gerade mal machen, "Set Value". Ich glaube, es war der Wert mit dem Index 2. Ich kann das schon aufrufen, aber ich kann den Missetäter sehr schnell finden, indem ich hier einen Break Point setze und den Code ausführe. Dann sehe ich ja, wer diesen Wert verändert. Das war vorher nicht möglich. Vorher musste ich im Code einfach alle Stellen suchen, die irgendwie potentiell in der Lage gewesen wären diesen Wert zu ändern. Jetzt kann ich mich hier um die Ausgabe kümmern. Auch hier, es wäre natürlich die Möglichkeit, dass ich diese Schleife in eine Prozedur, in eine Methode hier hineinverlege. Sowas nach dem Motto "public void print". Aber das ist keine gute Idee. Ich möchte meine Fachklasse Vektor nicht mit der Funktionalität des Ausdruck- ens in irgendeiner Weise überfrachten. Aber was ich jederzeit machen kann: Ich kann die Methode "To String" überschreiben. Jetzt kann ich in dieser Methode "To String" so eine Schleife machen: "I=0, i<this.length" jetzt brauche ich ein Resultat Das ist jetzt erst mal leer und jetzt kann ich an dieses Resultat diesen Wert anhängen. Und wenn das "I" klein genug ist, kann ich hier noch ein Komma anhängen. Und jetzt muss ich diesen String natürlich zurückgeben. So, jetzt habe ich eine wunderschöne Methode"To String". Und die kann ich jetzt verwenden, um hier die Werte von meinem Vektor auszugeben. Machen wir es so. Was haben wir erreicht? Der gesamte Code ist wesentlich besser lesbar. Nirgendwo in meinem Code muss ich mich irgendwie nochmal um die Länge meines Vektors scheren, außer da, wo ich den Vektor anlege. Ansonsten kann mir der Vektor auch selber sagen, wie lang er ist. Das Nächste ist, dass ich nicht mehr von außerhalb irgendetwas an dem Status von so einem Vektorobjekt ändern kann. Damit können wir diesen Abschnitt zusammenfassen. Wir haben zwei Konzepte kennengelernt. Das eine ist das Konzept der Separation of Concerns. Ich würde das auf Deutsch so übersetzen: "Jede Klasse kümmert sich um ihren eigenen Kram". In dem Fall ist es Verwaltung der Länge. Diese Klasse "Vektor" kümmert sich um ihren eigenen Kram und kann mit der Länge hier irgendwas machen. Also z.B. eine Abfrage, ob der Index auch wirklich erlaubt ist: "If indexthis.length" größer gleich "this.length" ist, dann kann hier irgendetwas passieren. Dieser Zustand ist ungültig. Ich kann z.B. eine Exception werfen mit irgendeiner Nachricht drin. Das ist die Separation of Concerns. Das Zweite ist die Kapselung. Der Status von Objekten ist privat, kann privat gehalten werden. Niemand kann es von außerhalb verändern. Niemand kann hier z.B. on the fly mal eben schnell die Länge von so einem Vektorobjekt verändern. Das ist gut so, weil das macht Software robuster. Soweit zu diesem Abschnitt über Separation of Concerns und Kapselung.

Visual C# 2012 Grundkurs

Schreiben Sie eigene Programme in C# und lernen Sie dazu alle Schlüsselwörter und die meisten Konstrukte kennen, um sicher mit dieser Programmierspreche umzugehen.

7 Std. 1 min (44 Videos)
Derzeit sind keine Feedbacks vorhanden...
 

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!