Questo è quello che vorrei fare:
Retain link come una classe astratta, utilizzare una fabbrica per istanziare e passare in chiusura/metodo anonimo come parametro per il metodo di costruzione della fabbrica. In questo modo, puoi mantenere il tuo progetto originale con Link come una classe astratta, forzando l'implementazione attraverso la fabbrica e nascondendo comunque qualsiasi traccia concreta di Link all'interno della fabbrica.
Ecco qualche esempio di codice:
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: In realtà, questo può essere un po 'più vicino a ciò che si vuole:
Link link = new Link.Builder
{
OnClick =() =>
{
// SetResponsePage(...);
},
OnFoo =() =>
{
// Foo!
}
}.Build("id");
Il bello è che utilizza un blocco di init, consentendoti di dichiarare il numero di implementazioni opzionali di azioni all'interno della classe Link che desideri.
Ecco la classe Link pertinente (con classe interna Costruttore sigillato).
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;
}
}
Questa è vicino a quello che stai cercando, ma penso che possiamo fare un ulteriore passo avanti con argomenti predefiniti opzionali, una caratteristica C# 4.0. Diamo un'occhiata a l'esempio di dichiarazione di Link con argomenti con nome opzionali:
Link link = Link.Builder.Build("id",
OnClick:() =>
{
// SetResponsePage(...);
Console.WriteLine("Click!");
},
OnFoo:() =>
{
Console.WriteLine("Foo!");
Console.ReadLine();
}
);
Perchè questo è cool? Diamo un'occhiata alla nuova classe Link:
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;
}
}
All'interno del Generatore di classe statica, v'è un metodo di costruzione fabbrica che prende in 1 parametro richiesto (L'ID) e 3 parametri opzionali, OnClick, OnFoo e OnBar. Se non vengono assegnati, il metodo factory fornisce loro un'implementazione predefinita.
Quindi, negli argomenti dei parametri del costruttore per Link, è necessario solo implementare i metodi necessari, altrimenti utilizzeranno l'azione predefinita, che potrebbe essere nulla.
Lo svantaggio, tuttavia, è nell'esempio finale, la classe Link non è astratta. Ma non può essere istanziato al di fuori dell'ambito della classe Link, perché il suo costruttore è privato (Forzando l'uso della classe Builder per istanziare Link).
Si potrebbe anche spostare direttamente i parametri facoltativi nel costruttore di Link, evitando la necessità di una fabbrica del tutto.
Non vedo una classe interiore anonima nell'esempio che hai dato. Se si desidera che gli implementatori della classe astratta implementino sempre alcuni metodi, è possibile creare un metodo astratto nella classe o implementare un'interfaccia. – tenor
@tenor, esiste una classe anonima inline definita che eredita da 'Link' e sovrascrive il metodo' onClick'. A differenza di Java, C# non supporta le classi anonime per derivare da un determinato tipo di utente. –
@Darin Dimitrov, grazie per averlo indicato. Stavo cercando una vera classe "interiore/nidificata". L'esempio fornito assomiglia più ad una classe anonima che deriva da una classe esistente, almeno nel linguaggio C#. – tenor