oopErste Schritte mit oop


Bemerkungen

Objektorientierte Programmierung (OOP) ist ein Programmierparadigma, das auf dem Konzept von "Objekten" basiert, das Daten in Form von Feldern enthalten kann, die oft als Attribute bezeichnet werden. und Code in Form von Prozeduren, oft als Methoden bezeichnet.

Einführung

OOP - Objektorientierte Programmierung ist heutzutage ein weit verbreitetes Programmierparadigma. In OOP modellieren wir reale Probleme mithilfe von Objekten und deren Verhalten, um sie programmgesteuert zu lösen.

Es gibt vier Haupt- OOP-Konzepte

  1. Erbe
  2. Polymorphismus
  3. Abstraktion
  4. Verkapselung

Diese vier Konzepte werden zusammen verwendet, um Programme in OOP zu entwickeln.

Es gibt verschiedene Sprachen, die die objektorientierte Programmierung unterstützen. Die beliebtesten Sprachen sind

  • C ++
  • Java
  • C #
  • Python (Python ist nicht vollständig objektorientiert, verfügt aber über die meisten OOP-Funktionen)

OOP-Einführung

Einführung

Objektorientierte Programmierung (meist als OOP bezeichnet) ist ein Programmierparadigma zur Lösung von Problemen.
Das Schöne an einem OO (objektorientierten) Programm ist, dass wir das Programm als eine Reihe von Objekten betrachten, die miteinander kommunizieren, anstatt als sequentielles Skript, das bestimmten Anweisungen folgt.

Es gibt viele Programmiersprachen, die OOP unterstützen. Einige der beliebtesten sind:

  • Java
  • C ++
  • c #

Es ist auch bekannt, dass Python OOP unterstützt, es fehlen jedoch einige Eigenschaften.


OOP-Terminologie

Der grundlegendste Begriff in OOP ist eine Klasse .
Eine Klasse ist im Grunde ein Objekt , das einen Zustand hat und entsprechend seinem Zustand arbeitet.

Ein weiterer wichtiger Begriff ist eine Instanz .
Stellen Sie sich eine Klasse als Vorlage vor, mit der Instanzen von sich selbst erstellt werden. Die Klasse ist eine Vorlage und die Instanz (en) sind die konkreten Objekte.

Eine Instanz, die aus der Klasse A erstellt wurde, wird normalerweise als Typ A bezeichnet, genau wie der Typ von 5 int ist und der Typ von "abcd" eine Zeichenfolge ist .

Ein Beispiel für das Erstellen einer Instanz namens insance1 vom Typ (class) ClassA :

Java

ClassA instance1 = new ClassA();
 

C ++

ClassA instance1;
 

oder

ClassA *instance1 = new ClassA(); # On the heap
 

Python

instance1 = ClassA()
 

Wie Sie im obigen Beispiel sehen können, wurde in allen Fällen der Name der Klasse erwähnt, und danach gab es leere Klammern (außer C ++, wo die Klammern gelöscht werden können, wenn sie leer sind). In diesen Klammern können wir dem Konstruktor unserer Klasse arguments .

Ein Konstruktor ist eine Methode einer Klasse, die jedes Mal aufgerufen wird, wenn eine Instanz erstellt wird. Es kann Argumente annehmen oder nicht. Wenn der Programmierer keinen Konstruktor für eine Klasse angibt, die er erstellt, wird ein leerer Konstruktor erstellt (ein Konstruktor, der nichts tut).
In den meisten Sprachen ist der Konstruktor als Methode definiert, ohne seinen Rückgabetyp und mit demselben Namen der Klasse zu definieren (Beispiel in einigen Abschnitten).

Ein Beispiel zum Erstellen einer Instanz mit dem Namen b1 vom Typ (Klasse) ClassB . Der Konstruktor von ClassB benötigt ein Argument vom Typ int :

Java

ClassA instance1 = new ClassA(5);
 

oder

int i = 5;
ClassA instance1 = new ClassA(i);
 

C ++

ClassA instance1(5);
 

Python

instance1 = ClassA(5)
 

Wie Sie sehen, ist das Erstellen einer Instanz dem Aufruf einer Funktion sehr ähnlich.


Funktionen vs. Methoden

Beide Funktionen und Methoden sind sich sehr ähnlich, aber im Object Oriented Design (OOD) haben sie jeweils ihre eigene Bedeutung.
Eine Methode ist eine Operation, die für eine Instanz einer Klasse ausgeführt wird. Die Methode selbst verwendet normalerweise den Status der Instanz, um zu arbeiten.
Inzwischen gehört eine Funktion zu einer Klasse und nicht zu einer bestimmten Instanz. Das bedeutet, dass der Status der Klasse oder die in einer Instanz gespeicherten Daten nicht verwendet werden.

Von nun an werden wir unsere Beispiele nur in Java zeigen, da OOP in dieser Sprache sehr klar ist, die gleichen Prinzipien jedoch in jeder anderen OOP-Sprache funktionieren.

In Java hat eine Funktion das Wort statisch wie folgt:

// File's name is ClassA
public static int add(int a, int b) {
    return a + b;
}
 

Das heißt, Sie können es von überall im Skript aufrufen.

// From the same file
System.out.println(add(3, 5));

// From another file in the same package (or after imported)
System.out.println(ClassA.add(3, 5));
 

Wenn wir die Funktion aus einer anderen Datei aufrufen, verwenden wir den Namen der Klasse (in Java ist dies auch der Name der Datei), zu der sie gehört. Dies gibt die Intuition an, dass die Funktion zur Klasse gehört und nicht zu ihren Instanzen.

Im Gegensatz dazu können wir ein Verfahren in ClassA folgendermaßen definieren:

// File's name is ClassA
public int subtract(int a, int b){
    return a - b;
}
 

Nach dieser Deklaration können wir diese Methode wie folgt aufrufen:

ClassA a = new ClassA();
System.out.println(a.subtract(3, 5));
 

Hier mussten wir eine Instanz von ClassA erstellen, um die Methode subtract aufzurufen. Beachten Sie, dass wir Folgendes nicht tun können:

System.out.println(ClassA.subtract(3, 5));
 

Diese Zeile führt zu einem Kompilierungsfehler, der besagt, dass wir diese nicht statische Methode ohne Instanz aufgerufen haben.


Verwenden des Status einer Klasse

Nehmen wir an, wir wollen unsere Subtraktionsmethode erneut implementieren, aber diesmal möchten wir immer die gleiche Anzahl (für jede Instanz) subtrahieren. Wir können folgende Klasse erstellen:

class ClassB {

    private int sub_amount;

    public ClassB(int sub_amount) {
        this.sub_amount = sub_amount;
    }

    public int subtract(int a) {
        return a - sub_amount;
    }

    public static void main(String[] args) {
        ClassB b = new ClassB(5);
        System.out.println(b.subtract(3)); // Ouput is -2
    }
}
 

Wenn wir diesen Code ausführen, wird eine neue Instanz namens b der Klasse ClassB erstellt und der Konstruktor erhält den Wert 5 .
Der Konstruktor nimmt nun den angegebenen sub_amount und speichert ihn als sein eigenes privates Feld, auch als sub_amount bezeichnet (diese Konvention ist in Java sehr bekannt, um die Argumente den Feldern zu benennen).
Danach drucken wir das Ergebnis des Aufrufs der Methode subtract on b mit dem Wert 3 an die Konsole.

Beachten Sie, dass wir dies bei der Implementierung von subtract nicht verwenden this. wie im Konstruktor.
In Java muss this nur geschrieben werden, wenn eine andere Variable mit demselben Namen in diesem Bereich definiert ist. Dasselbe funktioniert mit Pythons self .
Wenn wir sub_amount in subtract verwenden, verweisen wir also auf das private Feld, das für jede Klasse unterschiedlich ist.

Ein weiteres Beispiel, das zu betonen ist.
Lassen Sie uns einfach die Hauptfunktion im obigen Code wie folgt ändern:

ClassB b1 = new ClassB(1);
ClassB b2 = new ClassB(2);

System.out.println(b1.subtract(10)); // Output is 9
System.out.println(b2.subtract(10)); // Output is 8
 

Wie wir sehen können, sind b1 und b2 unabhängig und haben jeweils ihren eigenen Zustand .


Schnittstellen und Vererbung

Eine Schnittstelle ist ein Vertrag, der definiert, welche Methoden eine Klasse haben wird, und somit ihre Fähigkeiten. Eine Schnittstelle hat keine Implementierung, sie definiert nur, was zu tun ist.
Ein Beispiel in Java wäre:

interface Printalbe {
    public void print();
}
 

Die Printalbe- Benutzeroberfläche definiert eine Methode namens print , gibt aber deren Implementierung nicht an (ziemlich seltsam für Java). Jede Klasse, die sich selbst als implementing dieser Schnittstelle deklariert, muss eine Implementierung der Draw-Methode bereitstellen. Zum Beispiel:

class Person implements Printalbe {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println(name);
    }
}
 

Wenn sich Person als Drawable deklariert , aber keine Implementierung zum Drucken zur Verfügung stellt , tritt ein Kompilierungsfehler auf, und das Programm kann nicht kompiliert werden.

Vererbung ist ein Begriff, der auf eine Klasse verweist erstreckt andere Klasse. Nehmen wir an, wir haben jetzt eine Person, die ein Alter hat. Eine Möglichkeit, eine solche Person zu implementieren, besteht darin, die Person- Klasse zu kopieren und eine neue Klasse mit dem Namen AgedPerson zu schreiben, die die gleichen Felder und Methoden hat, aber eine andere Eigenschaft hat.
Das wäre schrecklich, da wir unseren gesamten Code duplizieren, nur um unserer Klasse ein einfaches Feature hinzuzufügen.
Wir können Vererbung verwenden, um von Person zu erben und somit alle Funktionen zu erhalten, die dann mit unserer neuen Funktion verbessert werden können.

class AgedPerson extends Person {

    private int age;

    public AgedPerson(String name, int age) {
        super(name);
        this.age = age;
    }

    public void print() {
        System.out.println("Name: " + name + ", age:" + age);
    }
}
 

Es sind ein paar neue Dinge im Gange:

  • Wir haben die gespeicherten extends um anzuzeigen, dass wir von Person erben (und auch deren Implementierung in Printable , sodass die implementing Printable erneut deklariert werden muss).
  • Wir haben das Speichern Wort super Person ‚s Konstruktor aufzurufen.
  • Wir haben die Druckmethode von Person mit einer neuen überschrieben.

Dies wird ziemlich Java-technisch, so dass ich nicht näher auf dieses Thema eingehen werde. Ich möchte jedoch erwähnen, dass es viele extreme Fälle gibt, die vor dem Einsatz von Vererbung und Schnittstellen erlernt werden sollten. Welche Methoden und Funktionen werden beispielsweise vererbt? Was passiert mit privaten / öffentlichen / geschützten Feldern, wenn Sie von einer Klasse erben? und so weiter.

Abstrakte Klasse

Eine abstrakte Klasse ist ein ziemlich fortgeschrittener Begriff in OOP, der eine Kombination aus Schnittstellen und Vererbung beschreibt. Sie können eine Klasse schreiben, die sowohl implementierte als auch unimplementierte Methoden / Funktionen enthält. In Java geschieht dies mit dem Schlüsselwort abstract Ich werde es nicht mehr als ein schnelles Beispiel erklären:

abstract class AbstractIntStack {

    abstract public void push(int element);

    abstract public void pop();

    abstract public int top();

    final public void replaceTop(int element) {
        pop();
        push(element);
    }
}
 

Hinweis: Das final Schlüsselwort gibt an, dass Sie diese Methode nicht überschreiben können, wenn Sie von dieser Klasse erben. Wenn eine Klasse als final deklariert ist, kann keine Klasse von ihr erben.