Chaining (dt. Verkettung) ist ein Entwicklungskonstrukt bei dem Methodenaufrufe direkt aneinander “gekettet” werden. Chaining ist seit der Veröffentlichung von jQuery im Entwicklermainstream angekommen. Was für Webentwickler daily business ist, ist allerdings noch nicht in bei allen anderen Plattformen Gang und Gebe.
Mit einfachen Mitteln kann dennoch jeder .Net Entwickler seine Objekte chainable machen. Der von Eric Evans und Martin Fowler vorgeschlagene Weg zur Implementierung objekteorientierter Schnittstellen kurz “ fluent interfaces ” bietet den hierzu benötigten Ansatz ohne dass irgendwelche Frameworks oder Fremdsourcen in die eigene Solution integriert werden müssen.
Durch fluent interfaces können Objekte verkettet werden und die Schnittstellen sind lesbarer!
Anhand eines kleinen Beispiels sollte die Realisierung von Chaining in .Net klarer werden.
1: public interface IUiElement
2: { 3: void SetHeight(int height);
4: void SetWidth(int width);
5: void SetTitle(string title);
6: }
Verwendet wird eine Implementierung des IUiElement Interfaces demnach wie folgt
1: public void DoSomeUiActions(){ 2: IUiElement uiElement = new TextBox();
3: uiElement.SetHeight(20);
4: uiElement.SetWidth(100);
5: uiElement.SetTitle("Eine einfache Textbox"); 6: }
Mit dem fluent interfaces Ansatz würde das IUiElement allerdings so aussehen
1: public interface IUiElement
2: { 3: IUiElement SetHeight(int height);
4: IUiElement SetWidth(int width);
5: IUiElement SetTitle(string title);
6: }
Was auf den ersten Blick etwas gewöhnungsbedürftig für den alt eingesessenen .Net Entwickler wirkt, wird aber bei der Verwendung einer konkreten IUiElement Instanz klarer.
1: public void DoSomeUiAction()
2: { 3: IUiElement uiElement = new TextBox();
4: uiElement.SetHeight(20)
5: .SetWidth(100)
6: .SetTitle("chained textbox"); 7: }
Wie man direkt sieht wird der Code dadurch gestrafft und wirkt auch direkt schon logisch zusammenhängend.
Dieses Konstrukt kann sehr gut dabei helfen flexible Repositories zu erstellen, da Filter zum auslesen von Instanzen aus einem Repository einfach gechained werden können. Hier ein Beispiel dazu
1: public class UiElementService : IUiElementService
2: { 3: //...
4: IUiElementRepository repository;
5: // ...
6:
7: public UiElementService(IUiElementRepository repository)
8: { 9: this.repository = repository;
10: }
11: public List<IUiElement> GetElements()
12: { 13: return repository.GetUiElements().ToList<IUiElement>();
14: }
15: public List<IUiElement> GetElements(int height, string title)
16: { 17: return repository.GetUiElements()
18: .HeightEquals(height)
19: .TitleContains(title)
20: .ToList<IUiElement>();
21: }
22: }
23:
24: public class MockUpUiRepository : IUiElementRepository
25: { 26:
27: public IQueryable<IUiElement> GetUiElements()
28: { 29: TextBox tb = new TextBox();
30:
31: List<IUiElement> mockupElements = new List<IUiElement>()
32: { 33:
34: new TextBox() { 35: Height = 20,
36: Width = 110,
37: Title ="TextBox" },
38: new RadioButton() { 39: Height = 20,
40: Width = 200,
41: Title =".Net is cool?!"},
42: new CheckBox() { 43: Height = 19,
44: Width = 300,
45: Title="Test the checkbox"}
46: };
47: return mockupElements.AsQueryable();
48: }
49:
50:
51: }
52:
53: public static class UiRepositoryFilters
54: { 55: public static IQueryable<IUiElement> HeightEquals(
56: this IQueryable<IUiElement> query,
57: int height)
58: { 59: return (from e in query
60: where e.Height == height
61: select e);
62: }
63:
64: public static IQueryable<IUiElement> TitleContains(
65: this IQueryable<IUiElement> query,
66: string title)
67: { 68: return (from e in query
69: where e.Title.Contains(title)
70: select e);
71: }
72:
73: public static IQueryable<IUiElement> TitleStartsWith(
74: this IQueryable<IUiElement> query,
75: string title)
76: { 77: return (from e in query
78: where e.Title.StartsWith(title)
79: select e);
80: }
81: }
Wie man sieht ist das Chaining Konzept vielseitig und leicht einsetzbar, dadurch kann die Service-Fasade sehr flexible gestaltet werden. Die eigentliche Servicefasade kann dann sehr einfach in der Anwendung verwendet werden:
1: IUiElementService Service =
2: new UiElementService(new MockUpUiRepository());
3: Service.GetElements(20, "Net").ForEach(
4: delegate(IUiElement element)
5: { 6: Console.WriteLine(
7: String.Format("Element ({0}) | Weite ({1})", 8: element.Title,element.Height));
9: });
Mir persönlich gefällt der chaining Ansatz sehr gut, weil wie bereits gesagt, logisch zusammenhängende Aufrufe noch enger zusammenstehen im Code. Außerdem wird der Code dadurch um einiges straffer.
Was haltet Ihr von Chaining in .Net ?