Frage

Eine stolpert auf diesen Satz, wenn es um Design-Muster zu lesen.

Aber ich verstehe es nicht, könnte jemand das erklärt für mich?

War es hilfreich?

Lösung

  

Schnittstellen sind nur Verträge oder Unterschriften und sie nicht wissen,   etwas über Implementierungen.

Codierung gegen Schnittstelleneinrichtung, der Client-Code hält immer ein Interface-Objekt, das von einer Fabrik geliefert wird. Jede Instanz durch das Werk zurückgeschickt würde vom Typ Schnittstelle sein, die jede Fabrik Kandidatenklasse umgesetzt haben müssen. Auf diese Weise das Client-Programm ist nicht besorgt über die Umsetzung und die Schnittstelle Signatur bestimmt, welche alle Operationen durchgeführt werden können. Dies kann das Verhalten eines Programms zu ändern, während der Laufzeit verwendet werden. Es hilft Ihnen auch weit bessere Programme aus der Wartungs Sicht zu schreiben.

Hier ist ein einfaches Beispiel für Sie.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

[STAThread]
static void Main()
{
    //This is your client code.
    ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
    speaker.Speak();
    Console.ReadLine();
}

public interface ISpeaker
{
    void Speak();
}

public class EnglishSpeaker : ISpeaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : ISpeaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak German.");
    }

    #endregion
}

public class SpanishSpeaker : ISpeaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    #endregion
}

alt text

  

Dies ist nur ein einfaches Beispiel und   tatsächliche Erklärung des Prinzips ist   sprengt den Rahmen dieser Antwort.

EDIT

Ich habe das Beispiel oben und hinzugefügt aktualisiert eine abstrakte Lautsprecher Basisklasse. In diesem Update habe ich eine Funktion auf alle Spakers zu „SayHello“. Alle Lautsprecher sprechen „Hallo Welt“. Das ist also ein gemeinsames Merkmal mit ähnlicher Funktion. Siehe Klassendiagramm und Sie werden feststellen, dass Lautsprecher abstrakte Klasse iSpeaker Schnittstelle und markiert den Speak () als abstrakte, welche Mittel implementieren, dass die jeder Lautsprecher Implementierung für die Durchführung des Speak Verfahren verantwortlich ist, da sie von Lautsprecher zu Lautsprecher variiert. Aber alle Lautsprecher „Hallo“ sagen einstimmig. So in der Zusammenfassung Speaker Klasse definieren wir eine Methode, die „Hallo Welt“ und jeder Lautsprecher Implementierung sagt die SayHello-Methode abzuleiten.

ein Fall betrachtet, wo SpanishSpeaker kann nicht sagen, hallo so in diesem Fall, dass Sie die SayHello-Methode für spanische Lautsprecher außer Kraft setzen können und erhöhen die richtige Ausnahme.

  

Bitte beachten Sie, dass, haben wir   nicht gemacht Änderungen an Schnittstellen   ISpeaker. Und der Client-Code und   SpeakerFactory bleiben ebenfalls unberührt   unverändert. Und das ist, was wir von erreichen Programmier-to-Interface .

Und wir könnten dieses Verhalten erreichen, indem einfach eine Basis abstrakte Klasse Lautsprecher hinzufügen und einige kleinere Änderungen in jeder Implementierung somit unverändert das ursprüngliche Programm zu verlassen. Dies ist ein erwünschtes Merkmal jeder Anwendung und es macht Ihre Anwendung leicht wartbar.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //This is your client code.
        ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
        speaker.Speak();
        Console.ReadLine();
    }
}

public interface ISpeaker
{
    void Speak();
}

public abstract class Speaker : ISpeaker
{

    #region ISpeaker Members

    public abstract void Speak();

    public virtual void SayHello()
    {
        Console.WriteLine("Hello world.");
    }

    #endregion
}

public class EnglishSpeaker : Speaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        this.SayHello();
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : Speaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak German.");
        this.SayHello();
    }

    #endregion
}

public class SpanishSpeaker : Speaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public override void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    public override void SayHello()
    {
        throw new ApplicationException("I cannot say Hello World.");
    }

    #endregion
}

alt text

Andere Tipps

Denken Sie an eine Schnittstelle als ein Vertrag zwischen einem Objekt und seinen Kunden. Das ist die Schnittstelle gibt an die Dinge, die ein Objekt tun, und die Unterschriften für diese Dinge zugreifen.

Implementationen sind die tatsächlichen Verhaltensweisen. Nehmen wir zum Beispiel Sie haben eine Methode sort (). Sie können QuickSort oder MergeSort implementieren. Das sollte nicht Angelegenheit an den Client-Code Art so lange telefonieren wie die Schnittstelle ändert sich nicht.

Bibliotheken wie der Java-API und das .NET Framework machen die starke Nutzung von Schnittstellen, weil Millionen von Programmierern zur Verfügung gestellt, die Objekte verwenden. Die Schöpfer dieser Bibliotheken müssen sehr vorsichtig sein, dass sie die Schnittstelle nicht in diesen Bibliotheken zu den Klassen ändern, weil es alle Programmierer mit der Bibliothek auswirken wird. Auf der anderen Seite können sie die Umsetzung so viel ändern, da sie wie.

Wenn Sie als Programmierer, Sie Code gegen die Umsetzung dann, sobald es Ihren Code ändert sich nicht mehr funktioniert. Also denken Sie an den Vorteilen der Schnittstelle auf diese Weise:

  1. es versteckt die Dinge, die Sie brauchen nicht zu wissen, dass das Objekt einfacher zu bedienen.
  2. es bietet den Vertrag, wie das Objekt verhält, so dass Sie an diesem
  3. verlassen können

Es bedeutet, dass Sie sollten versuchen, den Code zu schreiben, so dass es eine Abstraktion (abstrakte Klasse oder Schnittstelle) verwendet anstelle der Implementierung direkt an.

Normalerweise wird die Umsetzung in Ihren Code durch den Konstruktor oder einen Methodenaufruf injiziert. So weiß der Code über die Schnittstelle oder eine abstrakte Klasse und kann alles nennen, die auf diesem Vertrag definiert ist. Als eigentliches Objekt (Implementierung der Schnittstelle / abstrakten Klasse) verwendet wird, arbeiten die Anrufe auf dem Objekt.

Dies ist eine Teilmenge der Liskov Substitution Principle (LSP), die L der SOLID Prinzipien.

Ein Beispiel in .NET würde mit IList zu Code anstelle von List oder Dictionary, so dass Sie jede Klasse verwenden könnten, dass Geräte IList austauschbar in Ihrem Code:

// myList can be _any_ object that implements IList
public int GetListCount(IList myList)
{
    // Do anything that IList supports
    return myList.Count();
}

Ein weiteres Beispiel aus der Base Class Library (BCL) ist die

Wenn Sie eine Auto-Klasse in Combustion-Car-Ära schreiben waren, dann ist es eine große Chance, dass Sie Ölwechsel () als Teil dieser Klasse implementieren würden. Aber, wenn Elektroautos eingeführt werden, würden Sie in Schwierigkeiten, da es keine Ölwechsel für diese Autos, und keine UMSETZUNG beteiligt ist.

Die Lösung des Problems ist ein performMaintenance () Schnittstelle in Car-Klasse und Details ausblenden innen angemessene Umsetzung zu haben. Jeder Autotyp würde seine eigene Implementierung für performMaintenance bieten (). Als Besitzer eines Autos alle müssen Sie behandeln ist performMaintenance () und nicht Sorge über die Anpassung, wenn eine Änderung gibt.

class MaintenanceSpecialist {
    public:
        virtual int performMaintenance() = 0;
};

class CombustionEnginedMaintenance : public MaintenanceSpecialist {
    int performMaintenance() { 
        printf("combustionEnginedMaintenance: We specialize in maintenance of Combustion engines \n");
        return 0;
    }
};

class ElectricMaintenance : public MaintenanceSpecialist {
    int performMaintenance() {
        printf("electricMaintenance: We specialize in maintenance of Electric Cars \n");
        return 0;
    }
};

class Car {
    public:
        MaintenanceSpecialist *mSpecialist;
        virtual int maintenance() {
            printf("Just wash the car \n");
            return 0;
        };
};

class GasolineCar : public Car {
    public: 
        GasolineCar() {
        mSpecialist = new CombustionEnginedMaintenance();
        }
        int maintenance() {
        mSpecialist->performMaintenance();
        return 0;
        }
};

class ElectricCar : public Car {
    public: 
        ElectricCar() {
             mSpecialist = new ElectricMaintenance();
        }

        int maintenance(){
            mSpecialist->performMaintenance();
            return 0;
        }
};

int _tmain(int argc, _TCHAR* argv[]) {

    Car *myCar; 

    myCar = new GasolineCar();
    myCar->maintenance(); /* I dont know what is involved in maintenance. But, I do know the maintenance has to be performed */


    myCar = new ElectricCar(); 
    myCar->maintenance(); 

    return 0;
}

Eine zusätzliche Erläuterung: Sie sind ein Autobesitzer, die mehrere Autos besitzt. Sie schnitzen den Service, den Sie auslagern möchten. In unserem Fall wollen wir die Wartungsarbeiten aller Autos auszulagern.

  1. Sie identifizieren den Vertrag (Interface), die gut für alle Ihre Autos und Service Provider hält.
  2. Service-Provider kommen mit einem Mechanismus, um den Service zu bieten.
  3. Sie wollen nicht zu Sorgen über den Fahrzeugtyp mit dem Service-Provider zugeordnet wird. Sie haben soeben angeben, wenn Sie auf Zeitplan Wartung und rufen Sie es möchten. Entsprechende Servicegesellschaft sollte springen und führen die Wartungsarbeiten.

    Alternative Ansatz.

  4. Sie identifizieren die Arbeit (kann eine neue Schnittstelle Schnittstelle sein), die gut für alle Ihre Autos hält.
  5. Sie kommen mit einem Mechanismus, um den Service zu bieten. Grundsätzlich Sie gehen, um die Umsetzung zu sorgen.
  6. Sie berufen sich auf die Arbeit und do it yourself. Hier können Sie gehen, um die Arbeit der entsprechenden Wartungsarbeiten zu tun.

    Was ist die Kehrseite des 2. Ansatzes? Sie sind möglicherweise nicht der Experte sein um den besten Weg zu finden, die Wartung zu tun. Ihre Aufgabe ist es, das Auto und genießen Sie es zu fahren. Nicht zu sein im Geschäft es aufrecht zu erhalten.

    Was es die Kehrseite des ersten Ansatzes? Es ist der Aufwand der Suche nach einer Firma usw. Wenn Sie ein Mietwagen-Unternehmen sind, ist es nicht der Mühe wert sein kann.

Diese Aussage ist über Kopplung. Ein möglicher Grund für die objektorientierte Programmierung verwendet, ist die Wiederverwendung. So zum Beispiel können Sie Ihren Algorithmus aufgeteilt zwischen zwei kollaborierenden Objekte A und B. Dies könnte für die spätere Schaffung eines anderen Algorithmus nützlich sein, die eine oder andere der beiden Objekte wiederverwendet werden könnten. Wenn jedoch diese Objekte kommunizieren (Senden von Nachrichten - Methoden aufrufen), schaffen sie untereinander Abhängigkeiten. Aber wenn man das eine ohne das andere verwenden möchten, müssen Sie angeben, was sollte ein anderes Objekt C tun tun für Objekt A, wenn wir B. Those Beschreibungen ersetzen sind Schnittstellen aufgerufen. Dies ermöglicht Objekt A ohne Änderung für die Kommunikation mit anderem Objekt auf der Schnittstelle zu verlassen. Die Aussage, die Sie erwähnt, sagt, dass, wenn Sie planen, einen Teil eines Algorithmus (oder allgemeiner ein Programm) wieder zu verwenden, sollten Sie Schnittstellen erstellen und auf sie verlassen, so dass Sie jederzeit die konkrete Umsetzung ohne Änderung anderer Objekte ändern können, wenn Sie die Verwendung erklärt Schnittstelle.

Wie andere gesagt haben, bedeutet dies, dass Ihre Berufung Code nur über eine abstrakt Eltern wissen sollte, nicht die tatsächliche Umsetzung der Klasse, die die Arbeit tun wird.

Was dies zu verstehen hilft, ist das Warum sollten Sie immer Programm mit einer Schnittstelle. Es gibt viele Gründe, aber zwei der am einfachsten zu erklären sind,

1) Prüfung.

Lassen Sie uns sagen, dass ich meine gesamte Datenbank-Code in einer Klasse haben. Wenn mein Programm kennt die konkrete Klasse, kann ich nur meinen Code testen, indem es wirklich gegen diese Klasse ausgeführt wird. Ich verwende. -> bedeutet „im Gespräch mit“

WorkerClass -> DALClass Lassen Sie uns jedoch eine Schnittstelle zu der Mischung hinzufügen.

WorkerClass -> IDAL. -> DALClass

So die DALClass implementiert die IDAL Schnittstelle und Arbeiter Klasse NUR diese Anrufe durch.

Wenn wir nun für den Code zu schreiben Tests wollen, könnten wir stattdessen eine einfache Klasse, dass wie eine Datenbank fungiert.

WorkerClass -> IDAL. -> IFakeDAL

2) Wiederverwendung

das obige Beispiel folgend, lassen Sie uns sagen, dass wir von SQL Server verschieben möchten (was unsere konkreten DALClass Anwendungen) zu MonogoDB. Dies würde große Arbeit, aber nicht, wenn wir haben auf eine Schnittstelle programmiert. In diesem Fall schreiben wir gerade die neue DB-Klasse und Veränderung (über das Werk)

WorkerClass -> IDAL -> DALClass

WorkerClass -> IDAL -> MongoDBClass

Schnittstellen beschreiben Fähigkeiten. beim Schreiben zwingend notwendig, Code, sprechen über die Funktionen, die Sie verwenden, anstatt bestimmte Arten oder Klassen.

scroll top