Question

Une tombe sur cette phrase lors de la lecture sur les modèles de conception.

Mais je ne comprends pas, quelqu'un pourrait-il expliquer cela pour moi?

Était-ce utile?

La solution

  

Interfaces sont des contrats ou signatures seulement et ils ne savent pas   rien implémentations.

Codage contre des moyens d'interface, le code client tient toujours un objet d'interface qui est fournie par une usine. Toute instance retournée par l'usine serait de type d'interface qui doit avoir mis en œuvre une classe candidat usine. De cette façon, le programme client ne craint pas la mise en œuvre et la signature d'interface détermine ce qui peut être fait toutes les opérations. Cela peut être utilisé pour modifier le comportement d'un programme à l'exécution. Il vous permet également d'écrire des programmes beaucoup mieux du point de vue de l'entretien.

Voici un exemple de base pour vous.

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
}

text alt

  

Ceci est juste un exemple de base et   explication réelle du principe est   au-delà de la portée de cette réponse.

EDIT

J'ai mis à jour l'exemple ci-dessus et a ajouté une classe de base abstraite Président. Dans cette mise à jour, j'ai ajouté une fonctionnalité à tous Spakers à « SayHello ». Tous parlent haut-parleur « Bonjour tout le monde ». Donc, c'est une caractéristique commune avec fonction similaire. Référez-vous au diagramme de classes et vous trouverez que le président classe abstraite et implémenter l'interface iSpeaker marque le Speak () comme abstraites qui signifie que la mise en œuvre de chaque Président est responsable de la mise en œuvre de la méthode Speak car elle varie d'une enceinte à. Mais tout orateur dire « Bonjour » à l'unanimité. Ainsi, dans la classe abstraite Président, nous définissons une méthode qui dit: « Bonjour tout le monde » et chaque implémentation Président dérivera la méthode SayHello.

Prenons un cas où SpanishSpeaker ne peut pas dire Bonjour donc dans ce cas, vous pouvez remplacer la méthode SayHello pour Président espagnol et raise exception appropriée.

  

S'il vous plaît noter que, nous avons   apporté aucune modification à l'interface   ISpeaker. Et le code client et   SpeakerFactory sont aussi maintenues   inchangé. Et voici ce que nous obtenons par Programmation à l'interface .

Et nous pourrions obtenir ce comportement en ajoutant simplement une classe abstraite de base et une modification Président mineur dans chaque mise en œuvre laissant ainsi le programme original inchangé. Ceci est une caractéristique souhaitée de toute application et rend votre application facilement maintenable.

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
}

text alt

Autres conseils

Pensez à une interface comme un contrat entre un objet et ses clients. C'est l'interface spécifie les choses qu'un objet peut faire, et les signatures d'accès à ces choses.

Implémentations sont les comportements réels. Disons, par exemple, vous avez une sorte de méthode (). Vous pouvez mettre en œuvre QuickSort ou mergesort. Cela ne devrait pas question au code client appelant sorte aussi longtemps que l'interface ne change pas.

Les bibliothèques comme l'API Java et .NET Framework utilisent énormément d'interfaces parce que des millions de programmeurs utilisent les objets fournis. Les créateurs de ces bibliothèques doivent être très prudents qu'ils ne changent pas l'interface aux classes dans ces bibliothèques, car cela affectera tous les programmeurs utilisant la bibliothèque. D'autre part, ils peuvent changer la mise en œuvre autant qu'ils aiment.

Si, en tant que programmeur, vous codez contre la mise en œuvre alors dès qu'il change votre code cesse de fonctionner. Alors, pensez aux avantages de l'interface ainsi:

  1. il cache les choses que vous n'avez pas besoin de savoir faire l'objet plus simple à utiliser.
  2. il fournit le contrat de la façon dont l'objet se comportera de sorte que vous pouvez compter sur cela

Cela signifie que vous devriez essayer d'écrire votre code afin qu'il utilise une abstraction (classe abstraite ou interface) au lieu de la mise en œuvre directement.

Normalement, la mise en œuvre est injecté dans votre code par le constructeur ou un appel de méthode. Donc, votre code connaît l'interface ou classe abstraite et peut appeler tout ce qui est défini sur ce contrat. Comme un objet réel (mise en œuvre de l'interface / classe abstraite) est utilisée, les appels fonctionnent sur l'objet.

Ceci est un sous-ensemble de la Liskov Substitution Principle (LSP), le L de la les principes de SOLID.

Un exemple dans .NET serait de code avec IList au lieu de List ou Dictionary, vous pouvez utiliser une classe qui implémente IList interchangeable dans votre code:

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

Un autre exemple de la classe de base Library (BCL) est le

Si vous deviez écrire une classe de voitures dans l'ère combustion de voitures, alors il y a une grande chance que vous mettre en œuvre oilChange () comme une partie de cette classe. Mais, quand les voitures électriques sont introduites, vous seriez en difficulté car il n'y a pas de changement d'huile impliqué pour ces voitures, et pas implemention.

La solution au problème est d'avoir un performMaintenance () Interface dans les détails de classe et cacher voiture dans la mise en œuvre appropriée. Chaque type de voiture fournirait sa propre mise en œuvre pour performMaintenance (). En tant que propriétaire d'une voiture tout ce que vous devez traiter est performMaintenance () et ne pas s'adapter quand il y a un changement.

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;
}

Explication supplémentaire: Vous êtes propriétaire d'une voiture qui est propriétaire de plusieurs voitures. Vous découpez le service que vous voulez sous-traiter. Dans notre cas, nous voulons externaliser les travaux d'entretien de toutes les voitures.

  1. Vous identifiez le contrat (Interface) qui est valable pour toutes vos voitures et les fournisseurs de services.
  2. Les fournisseurs de services viennent avec un mécanisme pour fournir le service.
  3. Vous ne voulez pas à vous soucier d'associer le type de voiture avec le fournisseur de services. Vous venez de spécifier si vous voulez l'entretien des horaires et l'invoquons. société de services appropriés devraient sauter et effectuer les travaux d'entretien.

    autre approche.

  4. Vous identifiez le travail (peut être une nouvelle interface Interface) qui est valable pour toutes vos voitures.
  5. sortir avec un mécanisme pour fournir le service. Fondamentalement, vous allez fournir la mise en œuvre.
  6. vous invoquez le travail et de le faire vous-même. Ici, vous allez faire le travail des travaux d'entretien approprié.

    Quel est l'inconvénient de la 2ème approche? Vous ne pouvez pas être l'expert à trouver la meilleure façon de faire l'entretien. Votre travail consiste à conduire la voiture et d'en profiter. Ne pas être dans l'entreprise de la maintenir.

    Ce que l'inconvénient de la première approche? Il y a les frais généraux de la recherche d'une entreprise, etc. Sauf si vous êtes une société de location de voiture, il peut ne pas être en vaut la peine.

Cette instruction est sur le couplage. L'une des raisons possibilité d'utiliser la programmation orientée objet est la réutilisation. Ainsi, par exemple, vous pouvez diviser votre algorithme entre les deux objets A et B. collaborateur Cela peut être utile pour la création ultérieure d'un autre algorithme, ce qui pourrait réutiliser une ou l'autre des deux objets. Cependant, lorsque ces objets communiquent (envoyer des messages - méthodes d'appel), ils créent des dépendances entre eux. Mais si vous voulez utiliser un sans l'autre, vous devez spécifier ce qui devrait faire un autre objet C faire pour objet A si l'on remplace B. Ces descriptions sont appelées interfaces. Cela permet à l'objet A de communiquer sans changement avec différents objets se fondant sur l'interface. La déclaration que vous avez mentionné dit que si vous avez l'intention de réutiliser une partie d'un algorithme (ou plus généralement un programme), vous devez créer des interfaces et compter sur eux, de sorte que vous pouvez changer la mise en œuvre concrète tout moment sans changer d'autres objets si vous utilisez la l'interface déclarée.

Comme d'autres l'ont dit, cela signifie que votre code d'appel ne devrait connaître un parent abstrait, pas la classe mise en œuvre réelle qui fera le travail.

Ce qui aide à comprendre c'est le pourquoi vous devriez toujours programme à une interface. Il y a de nombreuses raisons, mais deux des plus faciles à expliquer sont

1) Test.

Le mot Let je mon code toute la base de données dans une seule classe. Si mon programme connaît la classe concrète, je ne peux tester mon code en cours d'exécution vraiment contre cette classe. J'utilise -.> Signifie « parle à »

WorkerClass -> DALClass Cependant, nous allons ajouter une interface au mélange.

WorkerClass -> IDAL -.> DALClass

Ainsi, les DALClass implémente l'interface IDAL, et la classe des travailleurs appelle seulement à travers cela.

Maintenant, si nous voulons des tests d'écriture pour le code, nous pourrions faire à la place une classe simple qui agit comme simplement une base de données.

WorkerClass -> IDAL -.> IFakeDAL

2) Réutilisation

Suivant l'exemple ci-dessus, disons que nous voulons passer de SQL Server (qui nos DALClass en béton usages) à MonogoDB. Cela prendrait des travaux importants, mais pas si nous avons programmé une interface. Dans ce cas, nous écrivons simplement la nouvelle classe de DB, et le changement (par l'usine)

WorkerClass -> IDAL -> DALClass

à

WorkerClass -> IDAL -> MongoDBClass

interfaces décrivent les capacités. lors de l'écriture du code impératif, parler des capacités que vous utilisez, plutôt que des types ou des classes spécifiques.

scroll top