2010-07-19 13 views
14

Estos 2-3 últimos años, muchos proyectos que veo, como el código abierto C# CMS de Cuyahoga, tienden a definir clases persistentes y no persistentes como Interface. ¿Por qué? ¿Hay una buena razón? TDD? ¿Burlón? Un patrón de diseño? ...¿Por qué las clases tienden a definirse como interfaz hoy en día?

+7

¿por qué no? Pero no definen las clases _as_ interfaces. Los exponen a través de una interfaz. –

+0

@Henk, sí. Tienes razón. –

Respuesta

22

La razón principal es que esto hace que las técnicas como dependency injection sean más fáciles. Esto, a su vez, permite una mayor flexibilidad en el software y una reutilización y recombinación más sencillas del código existente. Los ejemplos para los que esto es útil incluyen las diversas formas de pruebas unitarias (como usted mencionó), pero también la mayoría de las otras formas de reutilización de código "regular".

Un ejemplo sencillo:

Digamos que tienes un método que calcula los salarios emplyoee. Como parte de su firma, acepta un objeto que calcula sus beneficios, digamos una instancia de BenefitCalculator:

calculateSalary(... BenefitCalculator bc, ...) 

Originalmente, su diseño tiene una sola clase BenefitCalculator. Pero luego, resulta que necesita más de una clase, p. porque se supone que diferentes partes del software usan diferentes algoritmos (tal vez para soportar diferentes países, o porque el algoritmo se supone que puede ser configurado por el usuario ...). En ese caso, en lugar de inflar la implementación existente de BenefitCalculator, tiene sentido crear nuevas clases, por ej. BenefitCalculatorFrance o BenefitCalculatorSimple etc.

Ahora bien, si se utiliza la firma

calculateSalary(... BenefitCalculator bc, ...) 

, que se atornillan clase de, porque no se puede suministrar diferentes implementaciones. Sin embargo, si se utiliza

calculateSalary (... IBenefitCalculator aC, ...)

sólo puede tener todas las clases de implementar la interfaz.

Esto es realmente solo un caso especial de "acoplamiento flojo": Exija lo menos posible de otras partes del código. En este caso, no exija una cierta clase; en su lugar, solo exija que existan ciertos métodos, que es exactamente lo que hace una interfaz.

+0

IIRC el término para esto es [acoplamiento libre] (http://en.wikipedia.org/wiki/Loose_coupling). –

+0

@Chris: Sí, lo es. Ver mi respuesta (último párrafo) :-). – sleske

+0

Ah, me perdí de leer eso originalmente. –

1

Las interfaces tienen la ventaja de que te hacen independiente de la implementación, lo cual es una buena cosa.

3

Antes que nada, no puede definir una clase como interfaz. Tu clase implementa una interfaz.

Las interfaces se utilizan como una forma de habilitar el comportamiento polimórfico. Cada clase que implementa la interfaz es libre de especificar su propia implementación de los métodos definidos en la interfaz. Tome lo siguiente, por ejemplo:

Está escribiendo software bancario. Su tarea es escribir un procesador de transacciones. Ahora, usted sabe que necesita manejar diferentes tipos de Transacciones (Depósitos, Retiros, Transferencias). Se puede escribir código que se parece a:

public class TransactionProcessor 
{ 
    public void ProcessDeposit(// Process Deposit); 
    public void ProcessWithdraw(// Process Withdraw); 
    public void ProcessTransfer(// Process Transfer); 
} 

Y entonces cada vez que alguien añade un nuevo tipo de transacción, tiene que modificar su clase.O bien, podría:

public interface ITransaction { void Process(); } 

public class TransactionProcessor 
{ 
    public void ProccessTransaction(ITransaction t) { t.Process(); } 
} 

Ahora no necesita modificar su código para procesar un nuevo tipo de transacción. Solo necesita personas para crear su propia clase que implemente ITransaction y su clase "solo lo manejará".

Esto le permite intercambiar implementaciones de una interfaz según sus necesidades. También permite cosas como Inyección de Dependencia y Marcos burlones para Pruebas unitarias.

En general, sin embargo, es solo otra manera de hacer que su código sea más flexible.

1

Durante los últimos años los contenedores IoC se vuelven bastante populares entre los desarrolladores. Por ejemplo, Unity Container de Microsoft Practices. Entonces, al inicio de su aplicación puede registrar clases concretas que implementan interfaces, y luego, por ejemplo, todas las clases que contienen estas interfaces en sus constructores, o sus propiedades marcadas con el atributo [Dependency] se llenarán cuando instalen objetos a través de Resolución del contenedor de la unidad Es bastante útil en las aplicaciones con dependencias complicadas, cuando una interfaz se puede implementar en tres clases diferentes. Y todo esto no se puede lograr sin el uso de interfaces.

0

En un nivel realmente aburrido las interfaces también pueden ayudar a hacer una compilación más rápida.

public class A { 
    B b; 
} 

public class B { 
    public int getCount() { 
     return 10; 
    } 
} 

En este caso se hacen cada vez que los cambios internos en B, el compilador tiene que volver a evaluar Un para determinar si es necesario volver a compilar.

En su lugar, utilizan interfaces:

class A { 
    IB b; 
} 

interface IB { 
    int getCount(); 
} 

class B : IB { 
    public int getCount() { 
     return 10; 
    } 
} 

En este caso Un solamente depende de IB. Ningún cambio en B requiere cualquier consideración de A en tiempo de compilación.

A escala este efecto en la evaluación de dependencia de cortocircuito puede acelerar significativamente la compilación de grandes bases de código. Es particularmente poderoso cuando hay muchas clases dependiendo de una sola clase que cambia mucho.

Claramente, este beneficio de tiempo de compilación solo funciona si las clases no tienen dependencia estática de las clases de implementación. Hacer lo siguiente frustraría totalmente este beneficio:.

class A { 
    IB b = new B(); 
} 

Aquí es donde la inyección de dependencias viene en el envase DI sería construir una B y proporcionarla a A como un IB así A doesn no es necesario tener la dependencia estática.

Cuestiones relacionadas