2009-04-06 14 views
6

¿Debería crear siempre una interfaz si existe la posibilidad de que haya algo más que pueda usarla, o esperar hasta que exista una necesidad real, entonces refactorizar para usar una interfaz?¿Debería crear una interfaz cuando allí (actualmente) solo va a haber una clase que la implemente?

programación a una interfaz en general, parece como un buen consejo, pero luego está YAGNI ...

supongo que tal vez depende de la situación. En este momento tengo un objeto que representa una carpeta que puede contener recetas u otras carpetas. En lugar de usar Folder directamente, ¿debería preocuparme por implementar algo como IContainer? En caso de que en el futuro quiera tener una receta que se refiera a otras recetas secundarias (por ejemplo, una receta de tarta de manzana que también es un recipiente para una receta de pastel de masa)

Respuesta

8

Siempre depende de la situación. Si SABES que va a haber otra clase utilizando la interfaz, entonces sí, crea la clase de interfaz para ahorrar tiempo más tarde. Sin embargo, si no está seguro (y la mayoría de las veces no lo está), espere hasta que lo necesite.

Ahora, eso no significa ignorar la posibilidad de la interfaz: piense en los métodos públicos del objeto y en el sentido de crear una interfaz más adelante, pero no atente su código con nada que no sea realmente NECESITAR.

+0

YAGNI, no vas a necesitarlo -> no vas a necesitarlo –

+1

Precisamente. Cada vez que pongo interfaces o lo que sea que 'por si acaso' resulten necesarias nunca exactamente. Pero tu kilometraje puede variar. –

2

Yo diría que depende más de cuántos lugares va a utilizar la clase, y menos sobre cuántas clases podrían posiblemente implementar la interfaz. Si solo está utilizando Carpeta en uno o dos lugares, yo diría que espere hasta que haya una necesidad real de la interfaz antes de implementarla y refactorizarla. Sin embargo, si Folder se va a usar en 100 lugares diferentes, entonces puede ahorrar algo de tiempo programando una interfaz por adelantado.

3

Siempre habrá una prueba que lo use, a la derecha (usted hace pruebas unitarias, ¿no?). Lo que significa que siempre son las clases N + 1 las que lo usan, donde N es el número de clases que usan su clase en la aplicación.

Otro propósito de la interfaz además de la inyección de dependencia es la separación de la preocupación para que su clase pueda implementar múltiples interfaces.

Tenga esto en cuenta, pero siempre puede tener la interfaz introducida más adelante a través de refactorización si no se implementó al principio.

+0

¿Qué sucede si la clase es lo suficientemente simple como para que un objeto simulado no sea necesario para la prueba unitaria (es decir, es lo suficientemente simple como para simplemente usar un objeto real)? – Davy8

+0

Nunca dije nada sobre objetos falsos, ¿verdad ?-) Todo lo que digo es que el número de clases que lo usan siempre es + 1 (prueba). Y acepto que las interfaces pueden introducirse más tarde mediante una simple refactorización. – topchef

+0

Ah, leí mal, "usa" no "implementa" – Davy8

2

Generalmente, no debe molestarse en crear una interfaz si solo una clase va a implementarla, incluso si anticipa una posible clase, ya que puede haber problemas de implementación que no aparecerán hasta que la clase sea realmente probado en un escenario, en cuyo caso una interfaz creada prematuramente puede tener demasiados memebrs o puede que le falte un miembro.

Por ejemplo, el equipo de .NET Framework Bas Class Library admitió haber diseñado prematuramente ICollection cuando incluía una propiedad SyncRoot. Para el genérico posterior ICollection<T> decidieron eliminarlo (http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx).

Si va a crear un objeto simulado que implemente la misma interfaz, entonces eso contará como una segunda implementación que justifica la creación de la interfaz. Sin embargo, no todas las pruebas unitarias garantizan una interfaz de estilo simulado.

2

Piense en una interfaz como un contrato para definir la semántica, o un concepto. Ese es un enfoque general y no es realmente específico de un idioma.En el contexto de OO, si está trabajando en un modelo de herencia único, hay un excelente caso para preferir las interfaces sobre las clases para definir su modelo de objetos, ya que esa única vía de superclase es bastante valiosa y desea guardarla para algo más "sustancial" que definir las propiedades que están expuestas en un objeto o métodos.

Tener semántica IContainer (contrato) es una razón bastante pobre para crear una interfaz fuera de su carpeta; es mejor tener su carpeta (si está haciendo una lógica no trivial) 'implementar' la interfaz IContainer o ICollection (probablemente ya existente) en los marcos centrales de su idioma.

Como siempre, la mejor opción depende bastante del problema específico. En el caso de sus recetas que también son carpetas (?!) Probablemente esté pensando en una relación padre-hijo, o composición, una semántica que puede (y debe) expresarse mediante interfaces si tendrá otros elementos en su sistema 'operar' en cosas que se componen utilizando ese tipo de semántica.

Hay un poco de sobrecarga (programación sabia) con interfaces, y, si te encuentras cuando termines con nada más que un conjunto de clases e interfaces Woof e IWoof, entonces sabrás que probablemente no lo hiciste Necesito expresar su problema en términos de interfaces. Las clases simples hubieran sido suficientes.

Como regla general, para cualquier I, debe tener al menos un par de clases concretas (con nombres más significativos que no sean IImpl, o).

Espero que ayude.

+0

Esto comió mis corchetes en ángulo: para cualquier Ixxx ... nombres que no sean IxxxImpl o XXX. – alphazero

+1

SO convierte sus corchetes en ángulo '<' '>' como si se tratara de un estilo html. Para evitar esto, usa los puntos de apoyo alrededor del personaje, –

1

Mucha gente ya ha esbozado consejos muy acertados. Una cosa que quisiera agregar es que si está buscando evitar dependencias duras directas en clases concretas, las interfaces le ayudarán proporcionando un acoplamiento flexible. Si está creando una arquitectura basada en plug-ins, las interfaces son definitivamente el camino a seguir. Además, si está planeando escribir pruebas unitarias una al lado de la otra o más adelante en la línea, probablemente se dará cuenta de que el código que llama a su (s) clase (s) de carpeta tendrá que llevar una implementación concreta para que el código de llamada sea comprobable . Si su implementación concreta de la (s) clase (s) de carpeta está hablando a su vez con un DB o un servicio, necesitará tener eso también en sus pruebas, lo que se volverá difícil de manejar muy rápidamente. Solo mis 2 centavos.

Cuestiones relacionadas