2010-07-15 11 views
9

Necesito crear sobrecargas para funciones en una interfaz existente sin afectar a los componentes que actualmente implementan o hacen uso de la interfaz (idealmente).Agregar nuevas funciones a una interfaz

Calculo que tengo un par de opciones:

simplificado interfaz original:

public interface IServerComponent 
{ 
    bool Add(int a, int b); 
} 

puedo añadir las nuevas funciones sobrecargadas a la interfaz y la fuerza de cada clase que implementa la interfaz de implementar las nuevas funciones.

public interface IServerComponent 
{ 
    bool Add(int a, int b); 
    bool Add(int a, int b, int c); 
} 

O puedo crear una nueva interfaz que implemente la interfaz original. A continuación, otras clases que hacen uso de los originales no tendrán que cambiar y nuevas clases pueden implementar la nueva interfaz ...

public interface IServerComponent2 : IServerComponent 
{ 
    bool Add(int a, int b, int c); 
} 

¿Cuál es la mejor práctica es esta situación? ¿Hay otras opciones disponibles?

Gracias

Respuesta

11

Si los nuevos métodos se pueden expresar en términos de los viejos métodos, puede utilizar los métodos de extensión:

// Original interface 
public interface IServerComponent 
{ 
    bool Add(int a, int b, int c); 
} 

// New overload 
public static class MyServerMethods 
{ 
    public static bool Add(this IServerComponent component, int a, int b) 
    { 
    return component.Add(a, b, 0); 
    } 
} 

Si los métodos no se pueden expresar así (es decir, realmente necesita ser implementado por los propios componentes), entonces recomendaría definir una nueva interfaz. Este enfoque tiene la máxima compatibilidad con versiones anteriores.

+0

+1 por mencionar los métodos de extensión – ram

+1

Los métodos de extensión va a funcionar, sino que también tendrá el efecto de extender la funcionalidad de la clase que implementa a través de otras clases que reducen la cohesión. Veo esto como una solución temporal en el mejor de los casos. En el caso donde no puede extender la clase, porque no tiene acceso a la fuente, entonces los métodos de extensión tienen sentido. Podría hacerlo de esta manera para actualizaciones menores a una base de código existente, pero ciertamente lo pondría en mi lista de refactorizaciones para la próxima versión principal. – tvanfosson

+2

Esto depende totalmente del diseño. Si agrega * nueva funcionalidad *, entonces estaría de acuerdo; pertenece a una interfaz. Si agrega * sobrecargas * (p. Ej., Funcionalidad casi idéntica, siempre expresable en términos de otras funciones), entonces no estoy de acuerdo. En este caso, los métodos de extensión permiten * ortogonalidad *, reduciendo la duplicación de código. [Joe Duffy] (http://www.bluebytesoftware.com/blog/2010/02/10/ExtensionMethodsAsDefaultInterfaceMethodImplementations.aspx) tiene una buena publicación de blog sobre el tema. –

4

Si su interfaz IServerComponent no se ha enviado aún o es una interfaz interna que solo implementan sus propias clases, y los nuevos miembros de la interfaz tienen sentido para todas las clases existentes que implementan la interfaz, cambie la interfaz existente.

De lo contrario, cree una interfaz IServerComponent2 que amplíe IServerComponent. IIRC esto es lo que recomiendan las Pautas de diseño del marco. Un ejemplo de esto se puede encontrar en .NET Framework en forma de la clase X509Certificate2.

Sin embargo, si los nuevos miembros se pueden implementar en términos de los miembros originales, se puede también utilizar extension methods:

public interface IServerComponent 
{ 
    bool Add(int a, int b); 
} 

public static class ServerComponentExtensions 
{ 
    public static bool Add(this IServerComponent isc, int a, int b, int c) 
    { 
     return isc.Add(a, b) && isc.Add(b, c) && isc.Add(c, a); 
    } 
} 
0

Depende del contexto - si hay muchas clases que implementan la interfaz original, o si está publicado, entonces la única forma práctica es introducir el nuevo. Por otro lado, tener solo una interfaz es mucho más limpio a largo plazo, por lo que yo diría que refactorice la existente si puede pagarla.

0

Si no necesita o no quiere cambiar las clases (ahora o en el futuro) que ya implementan la interfaz anterior, debe crear una segunda interfaz. Sin embargo, se siente más como un truco y puede darte un código menos intuitivo.

Además, posponer una refactorización nunca es una buena idea en mi experiencia. Entonces, si sospecha que necesitará implementar la interfaz más adelante, también puede modificar la existente y ahorrarse un poco de dolor de cabeza. Definitivamente la forma más limpia de hacerlo.

0

creo que mantiene una única interfaz es más fácil, pero el segundo enfoque con 2 interfaz es mejor, porque no todas las clases necesita implementar bool Add(int a, int b, int c);

1

Soy consciente de que su ejemplo es artificial pero quiero darle una respuesta artificial que es diferente de lo que estás expresando para que puedas pensar en ello de una manera diferente. En lugar de tener su método de interfaz operando en algo concreto, podría tener sentido trabajar en algo abstracto.

Por ejemplo

public interface IAddableThings 
{ 
    int a; 
    int b; 
} 

public interface IOtherAddableThings : IAddableThings 
{ 
    int a; 
    int b; 
} 

public interface IServerComponent 
{ 
    bool Add(IAddableThings things); 
} 

Si esto realmente es un complemento entonces creo que esto hace mucho más sentido, pero si es realmente más como Calcular(), entonces querría mover algunas o todas las que los métodos funcionan hasta los objetos IAddableThings.

public interface IAddableThings 
{ 
    int a; 
    int b; 
    bool CalculateMe(); 
} 
Cuestiones relacionadas