Cómo no usar interfaces en C #

Al diseñar una aplicación, a menudo necesitará utilizar interfaces y clases abstractas. Este artículo analiza algunos ejemplos comunes de "abuso de interfaz" y las estrategias que podemos utilizar para evitarlos. También analiza lo que se entiende por el principio "programa en una interfaz y no en una implementación".

¿Qué son las interfaces?

En primer lugar, comprendamos las interfaces y por qué son necesarias en la programación. Una interfaz es estrictamente un contrato; no tiene ninguna implementación. Una interfaz contiene solo declaraciones de miembros. Puede tener declaraciones de métodos pero no definiciones. Los miembros declarados en una interfaz deben implementarse en los tipos (clases y estructuras) que extienden o implementan la interfaz. Una interfaz no puede contener campos. Una interfaz no se puede serializar porque no puede tener miembros de datos. Como dije, una interfaz solo puede tener declaraciones y no definiciones.  

Evite realizar cambios en las interfaces 

Una clase o estructura que amplía una interfaz debe implementar todos sus miembros. Si la implementación cambia, su código seguirá funcionando. Sin embargo, si el contrato, es decir, la interfaz, cambia, entonces tendrá que cambiar las implementaciones de todos los tipos que extienden la interfaz. En otras palabras, cualquier cambio en la interfaz afectará a todos los tipos que amplían la interfaz. Los tipos que extienden la interfaz deben adherirse al contrato. Por lo tanto, use las interfaces solo cuando rara vez necesite cambiarlas. Además, generalmente es mejor crear una nueva interfaz que cambiar una existente. 

Programa a una interfaz, no a una implementación

Es posible que haya escuchado las palabras "programar en una interfaz y no en una implementación" de vez en cuando. Es posible que haya estado usando interfaces en su código, pero aún estaba programando para la implementación. Examinemos ahora la diferencia entre los dos enfoques.

Cuando está programando en una interfaz, usa la abstracción más genérica (una interfaz o una clase abstracta) en lugar de una implementación concreta. Dado que las interfaces garantizan la uniformidad, programar en una interfaz implica que puede manejar objetos similares de manera uniforme. Al hacerlo, está desacoplado de la implementación, es decir, sus implementaciones pueden variar. Esto también agrega flexibilidad a sus diseños.

El siguiente fragmento de código ilustra la programación en una interfaz. Considere una interfaz llamada IRepository que contiene la declaración de algunos métodos. Las clases ProductRepository y CustomerRepository amplían la interfaz de IRepository e implementan los métodos declarados en la interfaz de IRepository, como se muestra a continuación.

interfaz pública IRepository

    {

        // Algún código

    }

    ProductRepository de clase pública: IRepository

    {

        // Algún código

    }

    CustomerRepository de clase pública: IRepository

    {

        // Algún código

    }

El siguiente código se puede utilizar para crear una instancia de ProductRepository.

Repositorio de IRepository = new ProductRepository ();

La idea es que puede usar cualquier clase aquí que implemente la interfaz IRepository. Entonces, la siguiente declaración también es válida.

IRepository repository = new CustomerRepository ();

Cuando programa una implementación, esta uniformidad se pierde. En su lugar, normalmente tendrá algunas construcciones, como declaraciones "if..else" o "switch..case", para controlar el comportamiento en su código.

Evite el uso excesivo de interfaces

Asociar todas las clases con una interfaz no es una buena práctica. El uso excesivo de interfaces de esta manera crea una complejidad innecesaria, introduce redundancia de código, viola YAGNI y reduce la legibilidad y mantenibilidad del código base. Las interfaces se utilizan para agrupar objetos que tienen un comportamiento idéntico. Si los objetos no tienen un comportamiento idéntico, no hay necesidad de esta agrupación. Usar interfaces cuando no va a tener múltiples implementaciones es un ejemplo de uso excesivo de interfaces.

La creación de una interfaz para una clase que coincida con los miembros públicos de la clase es bastante común. Al hacerlo, no agrega ningún valor en absoluto, simplemente duplica la interfaz de la clase sin agregar ninguna abstracción real.

Veamos ahora un ejemplo de cómo se sobreutilizan las interfaces. Considere la siguiente interfaz denominada IProduct.

IProduct de interfaz pública

    {

        int Id {obtener; conjunto; }

        cadena ProductName {get; conjunto; }

        Precio doble {get; conjunto; }

        int Cantidad {obtener; conjunto; }

    }

La clase de producto amplía la interfaz de IProduct como se muestra a continuación.

Producto de clase pública: IProduct

    {

        public int Id {obtener; conjunto; }

        cadena pública ProductName {get; conjunto; }

        precio doble público {get; conjunto; }

        public int Cantidad {obtener; conjunto; }

    }

Claramente, no necesitamos la interfaz IProduct, ya que la interfaz y su implementación son idénticas. El código redundante es innecesario.

Veamos otro ejemplo. El siguiente fragmento de código muestra una interfaz llamada IProductManager que tiene la declaración de dos métodos, a saber, Guardar y Actualizar.

 interfaz pública IProductManager

    {

        void Save (producto de IProduct);

        Actualización nula (producto IProduct);

    }

La interfaz IProductManager contiene las declaraciones de los métodos públicos de la clase ProductManager. Así es como se ve la clase ProductManager.

 ProductManager de clase pública: IProductManager

    {

        public void Save (producto de IProduct)

        {

           // Escribe tu implementación aquí

        }

        Actualización de vacío público (producto de IProduct)

        {

            // Escribe tu implementación aquí

        }

    }

Las interfaces IProduct e IProductManager son ejemplos de uso excesivo de la interfaz. Ambas interfaces tienen una sola implementación y no agregan ningún valor en absoluto.

Al usar interfaces, puede eliminar los acoplamientos innecesarios en su código y hacer que su código sea fácilmente comprobable. Sin embargo, se debe evitar el uso excesivo de interfaces. Utilice interfaces solo cuando haya más de una implementación de ellas. También puede usar interfaces cuando tiene una clase que tiene muchos roles que desempeñar o que tiene múltiples responsabilidades. En este caso, su clase puede implementar varias interfaces, una para cada función.