Frage

Was ist die Abhängigkeit Inversionsprinzip und warum es wichtig ist?

War es hilfreich?

Lösung

Überprüfen Sie dieses Dokument aus. Das Dependency Inversion Principle

Es sagt im Grunde:

  • Hohe Module sollte nicht hängen von Low-Level-Module. Beide sollten auf Abstraktionen abhängen.
  • Abstraktionen sollte nie hängen von Einzelheiten. Details sollten auf Abstraktionen abhängen.

Wie, warum es wichtig ist, kurz gesagt:. Änderungen riskant sind, und durch ein Konzept abhängig anstatt auf einer Implementierung Sie die Notwendigkeit von Veränderungen bei Aufrufstellen reduzieren

effektiv reduziert die DIP Kopplung zwischen verschiedenen Teilen des Codes. Die Idee ist, dass, obwohl es gibt viele Möglichkeiten der Umsetzung, sagen, eine Logging-Einrichtung, wie Sie es sollte in der Zeit relativ stabil sein, verwenden würde. Wenn Sie eine Schnittstelle extrahieren, die das Konzept der Protokollierung darstellt, sollte diese Schnittstelle wesentlich stabiler seine in der Zeit als die Implementierung und Aufrufstellen viel weniger von Änderungen betroffen werden, sollten Sie machen könnten unter Beibehaltung oder dass Logging-Mechanismus erstreckt.

Mit dem auch was die Implementierung einer Schnittstelle abhängen, erhalten Sie die Möglichkeit, während der Laufzeit zu wählen, die Implementierung besser für Ihre Umgebung geeignet ist. In Abhängigkeit von den Fällen ist dies auch interessant sein kann.

Andere Tipps

Die Bücher Agile Softwareentwicklung, Grundsätze, Muster und Praktiken und Agile Prinzipien, Patterns und Practices in C # sind die besten Ressourcen für die Nutzung ursprünglichen Ziele zu verstehen und Motivationen hinter dem Dependency Inversion Principle. Der Artikel „Die Abhängigkeit Inversion-Prinzip“ ist auch eine gute Ressource, aber aufgrund der Tatsache, dass es sich um eine gekürzte Version eines Entwurfs, die schließlich seinen Weg in die zuvor erwähnten Bücher gemacht, läßt es einige wichtige Diskussion über das Konzept eines aus Paket und Schnittstelle Eigentum, die „zu einem Schnittstellenprogramm, nicht eine Implementierung“, um zu unterscheiden, dieses Prinzip von den allgemeineren beraten Schlüssel werden im Buch Design Patterns gefunden (Gamma, et al.).

eine Zusammenfassung dar, das Dependency Inversion Principle ist in erster Linie um Umkehr die herkömmliche Richtung der Abhängigkeiten von „higher level“ Komponenten „unteren Ebene“ Komponenten, so dass „unteren Ebene“ Komponenten sind abhängig von die Schnittstellen Besitz von den „höheren Ebene“ Komponenten. (Anmerkung:. „Higher level“ Komponente bezieht sich hier auf die Komponente erfordern externe Abhängigkeiten / Dienstleistungen, die nicht unbedingt seine konzeptuelle Position innerhalb einer geschichteten Architektur) Dabei ist Kopplung nicht reduziert so viel, wie es ist verschoben aus Komponenten, die theoretisch weniger wertvoll zu Komponenten sind, die theoretisch wertvoller sind.

Dies wird erreicht, indem Komponenten, des externen Abhängigkeiten erreicht wird in Bezug auf eine Schnittstelle zum Ausdruck, für das eine Implementierung muss durch die Verbraucher der Komponente zur Verfügung gestellt werden. Mit anderen Worten ausdrücken die definierten Schnittstellen, was durch die Komponente benötigt wird, nicht, wie Sie verwenden, um die Komponente (zum Beispiel „INeedSomething“, nicht „IDoSomething“).

Was die Abhängigkeit Inversion Prinzip bezieht sich nicht auf die einfache Praxis von Abhängigkeiten durch die Verwendung von Schnittstellen (z MyService → [ILogger ⇐ Logger]) abstrahiert. Während dies eine Komponente von dem spezifischen Implementierung Detail der Abhängigkeit abkoppelt, wird invertieren es nicht um die Beziehung zwischen dem Verbraucher und Abhängigkeit (z [MyService → IMyServiceLogger] ⇐ Logger.

Die Bedeutung der Abhängigkeit Inversion Prinzips kann bis zu einem singulären Ziel zu können, destilliert wird, um Software-Komponenten wiederverwenden, die für einen Teil ihrer Funktionalität auf externe Abhängigkeiten verlassen (Logging, Validierung etc.)

Im Rahmen dieses allgemeinen Ziels der Wiederverwendung, können wir zwei Unterarten Wiederverwendung umreißen:

  1. eine Softwarekomponente innerhalb mehrerer Anwendungen mit Unter Abhängigkeit Implementierungen (zB Sie haben einen DI-Container entwickelt und möchten die Protokollierung zur Verfügung zu stellen, wollen aber nicht zu koppeln Ihren Container zu einem bestimmten Logger so, dass jeder, verwendet Ihre Behälter gewählte Logging-Bibliothek auch verwenden haben).

  2. Der Einsatz von Software-Komponenten innerhalb einer sich entwickelnden Kontext (z haben Sie entwickelt Business-Logik-Komponenten, die die gleiche über mehrere Versionen einer Anwendung bleiben, wo die Details der Implementierung entwickeln sich).

Mit dem ersten Fall von Komponenten über mehrere Anwendungen, wie zum Beispiel mit einer Infrastruktur Bibliothek Wiederverwendung, ist das Ziel, eine Kern-Infrastruktur Notwendigkeit, Ihre Kunden zu schaffen, ohne Kopplung Ihre Verbraucher Unter Abhängigkeiten von Ihrer eigenen Bibliothek, da Abhängigkeiten von solchen Einnahme Abhängigkeiten erfordert Ihre Verbraucher als auch die gleichen Abhängigkeiten zu verlangen. Dies kann problematisch sein, wenn die Verbraucher von Ihrer Bibliothek eine andere Bibliothek für den gleichen Infrastrukturbedarf verwenden wählen (zB NLog vs. log4net), oder wenn sie wählen eine spätere Version der benötigten Bibliothek verwenden, die nicht rückwärtskompatibel mit der Version erforderlich von Ihrer Bibliothek.

Mit dem zweiten Fall der Wiederverwendung von Business-Logik-Komponenten (das heißt „geordneten Komponenten“), ist das Ziel, die Zusammenarbeit zu isolierenRe Domain Umsetzung Ihrer Anwendung von den sich ändernden Anforderungen Ihres Implementierungsdetails (das heißt Ändern / Aktualisieren Persistenz Bibliotheken, Messaging-Bibliotheken, Verschlüsselungsstrategien, etc.). Idealerweise die Umsetzung Ändern Details einer Anwendung sollten die Komponenten nicht brechen die Anwendung des Business-Logik eingekapselt wird.

Hinweis: Einige dieser zweite Fall zu beschreiben, als tatsächliche Wiederverwendung widersprechen können, Argumentation, dass Komponenten wie Business-Logik-Komponenten innerhalb eines einzigen sich entwickelnden Anwendung verwendet nur eine einzige Anwendung darstellt. Die Idee hierbei ist jedoch, dass jede Änderung der Details der Implementierung der Anwendung einen neuen Kontext macht und daher einen anderen Anwendungsfall, obwohl die eigentlichen Ziele als Isolation gegen Portabilität unterschieden werden können.

Während nach dem Dependency Inversion Principle in diesem zweiten Fall kann einige Vorteile bieten, sei darauf hingewiesen, dass sein Wert als wie Java und C # zu modernen Sprachen angewandt wird stark reduziert, vielleicht bis zu dem Punkt irrelevant zu sein. Wie bereits erwähnt, beinhaltet die DIP-Implementierungsdetails in separate Pakete vollständig zu trennen. Im Falle einer sich entwickelnden Anwendung jedoch nur unter Verwendung von Schnittstellen in Bezug auf die Business-Bereich definiert wird Schutz vor, um auf höherer Ebene Komponenten zu modifizieren aufgrund Bedürfnisse der Umsetzung Detailkomponenten, auch wenn die Details der Implementierung letztlich im gleichen Paket zu ändern. Dieser Teil des Prinzips spiegelt Aspekte, die mit der Sprache in Ansicht relevant waren, als das Prinzip kodifiziert wurde (d.h. C ++), die auf neuere Sprachen nicht relevant ist. Das heißt, liegt die Bedeutung des Dependency Inversion Principle in erster Linie mit der Entwicklung von wiederverwendbaren Software-Komponenten / Bibliotheken.

Eine längere Diskussion dieses Prinzips, wie es auf die einfache Nutzung von Schnittstellen betrifft, Dependency Injection und die abgetrennten Schnittstelle Muster gefunden werden können hier . Zusätzlich wird eine Diskussion darüber, wie bezieht sich das Prinzip dynamisch typisierten Sprachen wie JavaScript foudn werden hier .

Wenn wir Software-Anwendungen entwerfen können wir die niedrige Niveau Klassen die Klassen berücksichtigen, die Umsetzung Basis- und Primäroperationen (Plattenzugriff, Netzwerkprotokolle, ...) und hohe Klassen die Klassen, die komplexe Logik zu kapseln (Geschäftsabläufe, .. )..

Die letzten, die auf den niedrigen Pegel Klassen verlassen. Eine natürliche Art und Weise solche Strukturen umzusetzen wäre niedrigem Niveau Klassen zu schreiben und sobald wir sie haben die komplexen Klassen der höheren Ebene zu schreiben. Da Klassen der höheren Ebene in Bezug auf die anderen definiert werden scheint dies die logische Art und Weise, es zu tun. Aber dies ist nicht ein flexibles Design. Was passiert, wenn wir eine niedrige Level-Klasse ersetzen müssen?

Die Abhängigkeit Inversion Prinzip besagt, dass:

  • Hohe Module sollte nicht auf niedrigem Niveau Module ab. Beide sollten auf Abstraktionen abhängen.
  • Abstraktionen sollten sich nicht auf Details abhängen. Details sollten auf Abstraktionen abhängen.

Dieses Prinzip versucht, „invertieren“ die herkömmliche Vorstellung, dass hohe Module in der Software auf der unteren Ebene Module abhängen. Hier hohe Module besitzt die Abstraktion (zum Beispiel entscheiden, die Methoden der Schnittstelle), die von unterer Ebene Module implementiert ist. Wodurch geringere Module auf höherer Ebene Module abhängig.

Für mich ist die Abhängigkeit Inversion Prinzip, wie es in der offiziellen Artikel , ist wirklich ein fehlgeleiteter Versuch die Wiederverwendbarkeit von Modulen zu erhöhen, die sind von Natur aus weniger wiederverwendbar, sowie eine Art und Weise ein Problem in der Sprache C ++ zu umgehen.

Das Problem in C ++ ist, dass die Header-Dateien normalerweise Erklärungen von privaten Feldern und Methoden enthalten. Wenn also ein High-Level-C ++ Modul die Header-Datei für einen Low-Level-Modul enthält, wird es auf dem tatsächlichen Umsetzung abhängen Details dieses Moduls. Und das, natürlich, ist nicht eine gute Sache. Aber das ist kein Problem in den moderneren Sprachen heute häufig verwendet.

High-Level-Module ist von Natur aus weniger wiederverwendbar als Low-Level-Module, da erstere normalerweise mehr application / kontextspezifisch als letztere ist. Zum Beispiel kann eine Komponente, die einen UI-Bildschirm implementiert ist von höchster Ebene und auch sehr (vollständig?) Spezifisch für die Anwendung. eine solche Komponente in einer anderen Anwendung wiederverwendet werden versuchen, ist kontraproduktiv und kann nur zu Over-Engineering führen.

So ist die Schaffung einer eigenen Abstraktion auf der gleichen Ebene einer Komponente A, die auf einer Komponente B abhängt (was nicht auf A abhängt) kann nur erfolgen, wenn die Komponente A wirklich nützlich in verschiedenen Anwendungen wiederverwendet werden oder Kontexten. Ist dies nicht der Fall ist, dann DIP Anwendung wäre schlechtes Design.

Dependency Inversion gut angewandt gibt Flexibilität und Stabilität auf der Ebene der gesamten Architektur der Anwendung. Es erlaubt die Anwendung sicherer und stabiler zu entwickeln.

Traditionelle geschichtete Architektur

Traditionell eine geschichtete Architektur UI hing von der Business-Schicht und dies wiederum ist abhängig von der Datenzugriffsschicht.

http://xurxodev.com/content/images/2016/ 02 / Traditional-Layered.png

Sie müssen verstehen, Schicht, Paket, oder Bibliothek. Mal sehen, wie der Code wäre.

Wir würden die Datenzugriffsschicht eine Bibliothek oder ein Paket für haben.

// DataAccessLayer.dll
public class ProductDAO {

}

Und eine andere Bibliothek oder Paketschicht Geschäftslogik, die auf der Datenzugriffsschicht abhängig ist.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private ProductDAO productDAO;
}

Schichtenarchitektur mit Abhängigkeits Inversion

Die Abhängigkeit Inversion gibt folgende Möglichkeiten:

  

High-Level-Module soll nicht auf Low-Level-Module ab. Beide sollten auf Abstraktionen abhängen.

  

Abstraktionen soll nicht auf Details abhängen. Details sollten auf Abstraktionen abhängen.

Was ist die High-Level-Module und niedriges Niveau? Denken Module wie Bibliotheken oder Pakete, High-Level-Modul würde diejenigen, die traditionell Abhängigkeiten und niedriges Niveau haben, auf das sie abhängig ist.

Mit anderen Worten Modul hohe Niveau wäre, wenn die Aktion aufgerufen wird und niedriges Niveau, wo die Aktion durchgeführt wird.

Eine vernünftige Schlussfolgerung aus diesem Prinzip zu ziehen ist, dass es keine Abhängigkeit zwischen concretions sein sollte, aber es muss eine Abhängigkeit von einer Abstraktion sein. Aber nach dem Ansatz nehmen wir uns Investitionen falsche Anwendung werden können, hängen Abhängigkeit, sondern eine Abstraktion.

Stellen Sie sich vor, dass wir unseren Code anpassen, wie folgt:

Wir würden die Datenzugriffsschicht eine Bibliothek oder ein Paket für haben, die die Abstraktion zu definieren.

// DataAccessLayer.dll
public interface IProductDAO
public class ProductDAO : IProductDAO{

}

Und eine andere Bibliothek oder Paketschicht Geschäftslogik, die auf der Datenzugriffsschicht abhängig ist.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private IProductDAO productDAO;
}

Obwohl wir auf eine Abstraktion Abhängigkeit zwischen Unternehmen und den Datenzugriff bleibt gleich sind abhängig.

http://xurxodev.com/content/images/2016/ 02 / Traditional-Layered.png

Abhängigkeits Inversion zu erhalten, muss die Persistenz-Schnittstelle im Modul oder Paket definiert werden, in dem diese hohe Logik oder Domäne ist und nicht in dem Low-Level-Modul.

Zuerst definieren, was die Domänenschicht ist und die Abstraktion seiner Kommunikation definiert Ausdauer.

// Domain.dll
public interface IProductRepository;

using DataAccessLayer;
public class ProductBO { 
    private IProductRepository productRepository;
}

Nachdem die Persistenz-Schicht auf der Domäne abhängt, bekam jetzt invertieren, wenn eine Abhängigkeit definiert ist.

// Persistence.dll
public class ProductDAO : IProductRepository{

}

http://xurxodev.com/content/images/ 2016/02 / Dependency-Inversion-Layers.png

Vertiefen des Prinzip

Es ist wichtig, das Konzept gut zu assimilieren, die Vertiefung der Zweck und Nutzen. Wenn wir in mechanisch bleiben und den typischen Fall Repository lernen, werden wir nicht in der Lage sein, zu erkennen, wo wir das Prinzip der Abhängigkeit anwenden können.

Aber warum invertieren wir eine Abhängigkeit? Was ist das Hauptziel über konkrete Beispiele?

Eine solche allgemein ermöglicht die stabilsten Dinge, die auf weniger stabilen Dinge nicht abhängig sind, häufiger zu ändern.

Es ist leichter, der Persistenz-Typ entweder die Datenbank oder Technologie für den Zugriff auf die gleiche Datenbank als die Domänenlogik oder Aktionen mit Ausdauer zu kommunizieren entworfen geändert, wird. Aus diesem Grunde wird die Abhängigkeit umgekehrt, weil, da es einfacher ist, die Ausdauer zu ändern, wenn diese Änderung auftritt. Auf diese Weise werden wir nicht zu change die Domain. Die Domain-Schicht ist die stabilste von allen, weshalb es nicht auf irgendetwas hängen sollte.

Aber es ist nicht nur das Repository Beispiel. Es gibt viele Szenarien, in denen dieses Prinzip gilt und es gibt Architekturen basieren auf diesem Prinzip.

Architekturen

Es gibt Architekturen, bei denen die Abhängigkeit Inversion seiner Definition Schlüssel. In allen Bereichen ist es die wichtigste, und es ist Abstraktionen, die das Kommunikationsprotokoll zwischen der Domäne und dem Rest der Pakete oder Bibliotheken definiert anzeigt.

Sauber Architektur

Sauber Architektur die Domäne befindet sich im Zentrum befindet, und wenn Sie in die Richtung der Pfeile aussehen Abhängigkeit angibt, es ist klar, was sind die wichtigsten und stabilen Schichten. Die äußeren Schichten gelten als instabil Werkzeuge so vermeiden ihnen abhängig.

Hexagonal Architektur

Es geschieht auf die gleiche Weise mit der hexagonalen Architektur, wo die Domain auch im zentralen Teil und Häfen sind Abstraktionen der Kommunikation von dem Domino nach außen befindet. Auch hier ist es offensichtlich, dass die Domain ist die stabilste und traditionelle Abhängigkeit invertiert wird.

Im Grunde heißt es:

Klasse sollte auf Abstraktionen abhängen (z Schnittstelle, abstrakte Klassen), nicht spezifische Details (Implementierungen).

Ein viel klarer Weg, um die Abhängigkeit Inversion Prinzip zu erklären ist:

Ihre Module, die komplexe Geschäftslogik kapseln sollten nicht direkt auf anderen Modulen abhängen, die Business-Logik zu kapseln. Stattdessen sollten sie nur auf Schnittstellen zu einfachen Daten abhängig ist.

D.h., anstatt Ihre Klasse Logic die Implementierung wie Menschen in der Regel tun.

class Dependency { ... }
class Logic {
    private Dependency dep;
    int doSomething() {
        // Business logic using dep here
    }
}

Sie sollten wie etwas tun:

class Dependency { ... }
interface Data { ... }
class DataFromDependency implements Data {
    private Dependency dep;
    ...
}
class Logic {
    int doSomething(Data data) {
        // compute something with data
    }
}

Data und DataFromDependency sollten im selben Modul wie Logic leben, nicht mit Dependency.

Warum das?

  1. Die beiden Business-Logik-Module sind nun entkoppelt. Wenn Änderungen Dependency, brauchen Sie nicht Logic zu ändern.
  2. Verstehen, was Logic tut, ist eine viel einfachere Aufgabe. Es funktioniert nur auf das, was wie ein ADT aussieht
  3. Logic können nun mehr werden leicht getestet. Sie können nun direkt Data mit gefälschten Daten instanziiert und geben es in. Kein Bedarf für Mocks oder komplexe Test Gerüsten.

Gute Antworten und gute Beispiele sind bereits von anderen, die hier gegeben.

Der Grund DIP wichtig ist, weil es das OO-Prinzip „sorgt dafür, lose gekoppelte Design “.

Die Objekte in der Software sollten nicht in eine Hierarchie, wo einige Objekte der obersten Ebene diejenigen, abhängig von Low-Level-Objekten sind. Änderungen in Low-Level-Objekte werden dann kräuseln-through auf Ihre Top-Level-Objekte, die die Software sehr zerbrechlich für den Wandel macht.

Sie möchten, dass Ihre ‚Top-Level‘ Objekte sehr stabil und nicht zerbrechlich für den Wandel sein, daher müssen Sie die Abhängigkeiten invertieren.

Invertierung des Steuer (IOC) ist ein Design-Muster, bei dem ein Objekt übergeben wird, die Abhängigkeit von einem externen Rahmen, anstatt einen Rahmen für die Abhängigkeit zu stellen.

Pseudocode Beispiel mit traditionellen Lookup:

class Service {
    Database database;
    init() {
        database = FrameworkSingleton.getService("database");
    }
}

ähnlicher Code IoC:

class Service {
    Database database;
    init(database) {
        this.database = database;
    }
}

Die Vorteile von IoC sind:

  • Sie haben keine Abhängigkeit von einem zentralen Rahmen, so kann dies geändert werden, wenn gewünscht wird.
  • Da Objekte erstellt werden vorzugsweise durch Injektion, unter Verwendung von Schnittstellen, ist es einfach Einheit zu schaffen Tests, die Abhängigkeiten ersetzen Mock-Versionen.
  • Entkoppelung off-Code.

Der Punkt der Abhängigkeit Inversion ist wieder verwendbare Software zu machen.

Die Idee ist, dass statt zwei Teile des Codes auf sich angewiesen, sich auf einig abstrahierte Schnittstelle verlassen. Dann können Sie entweder Stück ohne den anderen wiederverwendet werden.

Der Weg, dies wird am häufigsten durch eine Umkehrung der Steuer (IOK) Container wie Spring in Java erreicht ist. In diesem Modell werden die Eigenschaften von Objekten einrichten über eine XML-Konfiguration anstelle der Objekte ausgehen und ihre Abhängigkeit zu finden.

Stellen Sie sich diesen Pseudo-Code ...

public class MyClass
{
  public Service myService = ServiceLocator.service;
}

MyClass hängt direkt sowohl auf der Service-Klasse und die Servicelocator Klasse. Es muss sowohl von denen, wenn man es in einer anderen Anwendung verwenden möchten. Nun stellen Sie diese ...

public class MyClass
{
  public IService myService;
}

Nun setzt MyClass auf einer einzigen Schnittstelle, die IService Schnittstelle. Wir würden lassen Sie die IoC-Container gesetzt tatsächlich den Wert dieser Variablen.

So, jetzt MyClass kann leicht in anderen Projekten wiederverwendet werden, ohne die Abhängigkeit von den anderen zwei Klassen zusammen mit ihm zu bringen.

Noch besser ist, Sie haben nicht die Abhängigkeiten von MyService zu ziehen, und die Abhängigkeiten der Abhängigkeiten, und die ... na ja, Sie bekommen die Idee.

Inversion of Control Container und der Dependency Injection Muster von Martin Fowler ist ein gutes Buch zu . Ich fand Head First Design Patterns ein tolles Buch für meinen ersten Ausflug in dem Lernen DI und andere Muster.

Dependency Inversion: Verlassen Sie sich auf Abstraktionen, nicht auf concretions

.

Invertierung der Steuerung: Haupt vs Abstraktion, und wie die Haupt ist der Klebstoff der Systeme

.

DIP und IoC

Dies sind einige gute Beiträge sprechen darüber:

https: // coderstower. com / 2019/03/26 / abhängigkeits Inversion-why-you-shouldnt-avoid-it /

https://coderstower.com/ 2019/04/02 / Haupt- und Abstraktion-the-entkoppelt-peers /

https://coderstower.com/ 2019/04/09 / Inversion-of-Control-Putting-all-together /

Dependency Inversion Principle (DIP) sagt, dass

i) Hohe Module sollten nicht auf Low-Level-Module ab. Beide sollten auf Abstraktionen abhängen.

ii) Abstraktionen sollte nie hängen von Einzelheiten. Details sollten auf Abstraktionen abhängen.

Beispiel:

    public interface ICustomer
    {
        string GetCustomerNameById(int id);
    }

    public class Customer : ICustomer
    {
        //ctor
        public Customer(){}

        public string GetCustomerNameById(int id)
        {
            return "Dummy Customer Name";
        }
    }

    public class CustomerFactory
    {
        public static ICustomer GetCustomerData()
        {
            return new Customer();
        }
    }

    public class CustomerBLL
    {
        ICustomer _customer;
        public CustomerBLL()
        {
            _customer = CustomerFactory.GetCustomerData();
        }

        public string GetCustomerNameById(int id)
        {
            return _customer.GetCustomerNameById(id);
        }
    }

    public class Program
    {
        static void Main()
        {
            CustomerBLL customerBLL = new CustomerBLL();
            int customerId = 25;
            string customerName = customerBLL.GetCustomerNameById(customerId);


            Console.WriteLine(customerName);
            Console.ReadKey();
        }
    }

. Hinweis: Klasse auf Abstraktionen wie Schnittstelle oder abstrakte Klassen, nicht spezifische Details (Umsetzung der Schnittstelle) abhängen sollte

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top