Pregunta

Uno se topa con esta frase al leer acerca de los patrones de diseño.

Pero no entiendo, podría alguien explicar esto por mí?

¿Fue útil?

Solución

  

Las interfaces son sólo contratos o las firmas y no saben   nada acerca de las implementaciones.

Codificación contra medios de interfaz, el código de cliente tiene siempre un objeto de interfaz que es suministrada por una fábrica. Cualquier instancia devuelta por la fábrica sería de interfaz tipo que cualquier clase de candidato deberá haber aplicado la fábrica. De esta manera el programa cliente no está preocupado por la aplicación y la firma de interfaz determina lo que todas las operaciones se pueden realizar. Esto se puede utilizar para cambiar el comportamiento de un programa en tiempo de ejecución. También le ayuda a escribir mucho mejores programas desde el punto de vista del mantenimiento.

Aquí hay un ejemplo básico para usted.

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

  

Esto es sólo un ejemplo básico y   explicación real del principio es   más allá del alcance de esta respuesta.

editar

I han actualizado el ejemplo anterior y se añadió una clase abstracta de base del altavoz. En esta actualización, he añadido una función para todos los Spakers a "SayHello". Todo orador hablar "Hello World". Así que esa es una característica común con función similar. Consulte el diagrama de clase y usted encontrará que el altavoz clase abstracta implementa la interfaz ISpeaker y marcas del Habla () como abstractas, esto es que la aplicación de cada altavoz es responsable de implementar el método Habla ya que varía de un altavoz a otro. Pero todo orador decir "Hola" por unanimidad. Así que en la clase abstracta del altavoz se define un método que dice "Hello World" y cada aplicación altavoz derivará el método SayHello.

Considere un caso en SpanishSpeaker puede no dejar uno por lo que en ese caso se puede reemplazar el método SayHello para el altavoz español y elevar una excepción adecuada.

  

Tenga en cuenta que, tenemos   No hizo ningún cambio en la interfaz   ISpeaker. Y el código de cliente y   SpeakerFactory también se verán afectados   sin alterar. Y esto es lo que logramos por Programación-a-Interface .

Y que podría conseguir este comportamiento por simple adición de una base de altavoces clase abstracta y algunas modificaciones de menor importancia en cada aplicación dejando así el programa original sin cambios. Esta es una característica deseada de cualquier aplicación y que hace que su aplicación fácil de mantener.

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

Otros consejos

Piense en una interfaz como un contrato entre un objeto y sus clientes. Esa es la interfaz especifica las cosas que un objeto puede hacer, y las firmas para acceder a esas cosas.

Las implementaciones son los comportamientos reales. Digamos, por ejemplo, tiene un método sort (). Puede implementar QuickSort o mergesort. Eso no debería importar al código de cliente que llama especie, siempre y cuando la interfaz no cambia.

Las bibliotecas como la API de Java y .NET Framework hacen un uso intensivo de las interfaces, porque millones de programadores utilizan los objetos proporcionados. Los creadores de estas bibliotecas tienen que tener mucho cuidado de no cambiar la interfaz a las clases en estas bibliotecas, ya que afectará a todos los programadores que utilizan la biblioteca. Por otro lado se puede cambiar la implementación tanto como les gusta.

Si, como programador, código en contra de la aplicación a continuación, tan pronto como se cambia el código deja de funcionar. Así que pensar en los beneficios de la interfaz de esta manera:

  1. oculta las cosas que no necesita saber lo que el objeto más fácil de usar.
  2. que proporciona el contrato de cómo se comportará el objeto para que pueda confiar en que

Esto significa que usted debe tratar de escribir el código por lo que utiliza una abstracción (clase abstracta o interfaz) en lugar de la aplicación directamente.

Normalmente, la aplicación se inyecta en su código a través del constructor o una llamada al método. Por lo tanto, su código sabe acerca de la interfaz o clase abstracta y puede llamar a cualquier cosa que se define en el presente contrato. Como un objeto real (aplicación de la clase de interfaz / abstract) se utiliza, las llamadas están operando en el objeto.

Este es un subconjunto de la Liskov Substitution Principle (LSP), la L de la principios SOLID .

Un ejemplo de .NET sería la de código con IList en lugar de List o Dictionary, así que podría usar cualquier clase que implemente IList indistintamente en el código:

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

Otro ejemplo de la biblioteca de clases de Base (BCL) es la ProviderBase clase abstracta - esto proporciona algún tipo de infraestructura, y de importante significa que todas las implementaciones de proveedores se pueden utilizar indistintamente si el código en contra de ella

.

Si se va a escribir una clase de coches en la era de combustión-coches, entonces hay una gran probabilidad de que se implementaría oilChange () como una parte de esta clase. Sin embargo, cuando se introducen los coches eléctricos, que estaría en problemas ya que no hay cambio de aceite que supone para estos coches, y no hay IMPLEMENTACIÓN.

La solución al problema es tener un performMaintenance () Interfaz de coches de clase y ocultar los detalles en el interior adecuada implementación. Cada tipo de coches proporcionaría su propia implementación de performMaintenance (). Como propietario de la totalidad de un coche que tiene que tratar es performMaintenance () y no preocuparse por la adaptación cuando hay un cambio.

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

explicación adicional: Usted es propietario de un vehículo que posee varios coches. A forjar el servicio que desea externalizar. En nuestro caso queremos externalizar el trabajo de mantenimiento de todos los vehículos.

  1. Se identifica el contrato (interfaz) que es válido para todos los coches y proveedores de servicios.
  2. Los proveedores de servicios vienen con un mecanismo para prestar el servicio.
  3. Usted no quiere que preocuparse acerca de cómo asociar el tipo de coche con el proveedor de servicios. Sólo tiene que especificar cuando se desea programar el mantenimiento y la invocan. empresa de servicios apropiada debe saltar y realizar los trabajos de mantenimiento.

    enfoque alternativo.

  4. A identificar el trabajo (puede ser una nueva interfaz Interface) que es válido para todos los coches.
  5. salir con un mecanismo para prestar el servicio. Básicamente se va a proporcionar a la aplicación.
  6. se invoca el trabajo y hacerlo usted mismo. Aquí se va a hacer el trabajo de los trabajos de mantenimiento apropiado.

    ¿Cuál es la desventaja del segundo enfoque? Puede que no sea el experto en encontrar la mejor manera de hacer el mantenimiento. Su trabajo consiste en conducir el coche y disfrutar de ella. Por no estar en el negocio de mantenimiento de la misma.

    Lo que el lado negativo del primer enfoque? No es la sobrecarga de la búsqueda de una empresa, etc. A menos que usted es una empresa de alquiler de coches, puede que no sea la pena el esfuerzo.

Esta declaración es de acoplamiento. Una posible razón para el uso de la programación orientada a objetos es la reutilización. Así, por ejemplo, puede dividir su algoritmo entre los dos colaboradora objetos A y B. Esto podría ser útil para la creación posterior de otro algoritmo, lo que podría volver a utilizar uno u otro de los dos objetos. Sin embargo, cuando esos objetos se comunican (enviar mensajes - Métodos de llamadas), crean dependencias entre sí. Pero si desea utilizar una sin la otra, es necesario especificar lo que debe hacer algún otro objeto C hacer por objeto A si sustituimos B. Esas descripciones se llaman interfaces. Esto permite que el objeto A para comunicarse sin cambio con diferente objeto depender de la interfaz. La declaración que usted ha mencionado dice que si va a volver a utilizar una parte de un algoritmo (o más generalmente un programa), se debe crear interfaces y confiar en ellos, por lo que podría cambiar la aplicación concreta cualquier momento sin cambiar otros objetos si se utiliza el interfaz declarado.

Como otros han dicho, esto significa que su código de llamada sólo debe saber acerca de un padre abstracta, no la clase que implementa real que va a hacer el trabajo.

Lo que ayuda a entender este es el por qué usted debe programar siempre a una interfaz. Hay muchas razones, pero dos de los más fáciles de explicar están

1) Pruebas.

Vamos a decir que tengo toda mi código de base de datos en una clase. Si mi programa conoce la clase concreta, sólo puedo probar mi código por realmente ejecutarlo en contra de esa clase. Estoy usando -.> Para significar "habla"

WorkerClass -> DALClass Sin embargo, vamos a añadir una interfaz a la mezcla.

WorkerClass -> IDAL -.> DALClass

Así que los implementos DALClass la interfaz IDAL, y la clase trabajadora llamadas sólo a través de este.

Ahora bien, si queremos pruebas de escritura para el código, que podría en lugar de hacer una clase simple que simplemente actúa como una base de datos.

WorkerClass -> IDAL -.> IFakeDAL

2) Reutilización

Siguiendo el ejemplo anterior, supongamos que queremos pasar de SQL Server (que nuestros usos concretos DALClass) a MonogoDB. Esto llevaría obra importante, pero no si hemos programado para una interfaz. En ese caso, simplemente escribimos la nueva clase DB, y el cambio (a través de la fábrica)

WorkerClass -> IDAL -> DALClass

a

WorkerClass -> IDAL -> MongoDBClass

las interfaces describen capacidades. al escribir código imperativo, hablar acerca de las capacidades que está utilizando, en lugar de tipos o clases específicas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top