Esto es lo que haría:
Permanencia Enlace como una clase abstracta, utilizan una fábrica instanciarlo y procesar el cierre de método/anónimo como un parámetro para el método de aumento de la fábrica. De esta manera, puede mantener su diseño original con Link como una clase abstracta, forzando la implementación a través de la fábrica, y aún ocultando cualquier rastro concreto de Link dentro de la fábrica.
Aquí es un código de ejemplo:
class Program
{
static void Main(string[] args)
{
Link link = LinkFactory.GetLink("id",() =>
// This would be your onClick method.
{
// SetResponsePage(...);
Console.WriteLine("Clicked");
Console.ReadLine();
});
link.FireOnClick();
}
public static class LinkFactory
{
private class DerivedLink : Link
{
internal DerivedLink(String id, Action action)
{
this.ID = id;
this.OnClick = action;
}
}
public static Link GetLink(String id, Action onClick)
{
return new DerivedLink(id, onClick);
}
}
public abstract class Link
{
public void FireOnClick()
{
OnClick();
}
public String ID
{
get;
set;
}
public Action OnClick
{
get;
set;
}
}
}
EDIT: En realidad, esto puede ser un poco más cerca de lo que quiere:
Link link = new Link.Builder
{
OnClick =() =>
{
// SetResponsePage(...);
},
OnFoo =() =>
{
// Foo!
}
}.Build("id");
La belleza es que utiliza un bloque init, permitiéndote declarar tantas implementaciones opcionales de acciones dentro de la clase Link como quieras.
Aquí está la clase de enlace relevante (con clase interna de Builder sellada).
public class Link
{
public sealed class Builder
{
public Action OnClick;
public Action OnFoo;
public Link Build(String ID)
{
Link link = new Link(ID);
link.OnClick = this.OnClick;
link.OnFoo = this.OnFoo;
return link;
}
}
public Action OnClick;
public Action OnFoo;
public String ID
{
get;
set;
}
private Link(String ID)
{
this.ID = ID;
}
}
Esto se acerca a lo que estás buscando, pero creo que podemos dar un paso más allá con argumentos con nombre opcional, una característica de C# 4.0. Veamos la declaración de ejemplo de Enlace con argumentos con nombre opcionales:
Link link = Link.Builder.Build("id",
OnClick:() =>
{
// SetResponsePage(...);
Console.WriteLine("Click!");
},
OnFoo:() =>
{
Console.WriteLine("Foo!");
Console.ReadLine();
}
);
¿Por qué es genial? Vamos a ver la nueva clase Enlace:
public class Link
{
public static class Builder
{
private static Action DefaultAction =() => Console.WriteLine("Action not set.");
public static Link Build(String ID, Action OnClick = null, Action OnFoo = null, Action OnBar = null)
{
return new Link(ID, OnClick == null ? DefaultAction : OnClick, OnFoo == null ? DefaultAction : OnFoo, OnBar == null ? DefaultAction : OnBar);
}
}
public Action OnClick;
public Action OnFoo;
public Action OnBar;
public String ID
{
get;
set;
}
private Link(String ID, Action Click, Action Foo, Action Bar)
{
this.ID = ID;
this.OnClick = Click;
this.OnFoo = Foo;
this.OnBar = Bar;
}
}
Dentro del constructor de clase estática, existe un método de construcción de la fábrica que lleva en 1 parámetro requerido (El ID) y 3 parámetros opcionales, onclick, OnFoo y enclavar. Si no están asignados, el método de fábrica les da una implementación predeterminada.
Por lo tanto, en los argumentos del parámetro del constructor para el Enlace, solo se requiere implementar los métodos que necesita, de lo contrario utilizarán la acción predeterminada, que podría no ser nada.
El inconveniente, sin embargo, es en el ejemplo final, la clase de enlace no es abstracta. Pero no se puede instanciar fuera del alcance de la clase Link, porque su constructor es privado (Forzando el uso de la clase Builder para instanciar Link).
También podría mover los parámetros opcionales al constructor de Link directamente, evitando la necesidad de una fábrica en conjunto.
No veo una clase interna anónima en el ejemplo que usted dio. Si desea que los implementadores de su clase abstracta implementen siempre algunos métodos, puede crear un método abstracto en la clase o implementar una interfaz. – tenor
@tenor, hay una clase anónima en línea definida que hereda de 'Enlace' y anula el método' onClick'. A diferencia de Java, C# no admite clases anónimas para derivar de un tipo de usuario dado. –
@Darin Dimitrov, gracias por señalar eso. Estaba buscando una verdadera clase "interna/anidada". El ejemplo proporcionado se parece más a una clase anónima que se deriva de una clase existente, al menos en la jerga de C#. – tenor