252. Implementing a fluent syntax - part 5

טוב, זה כנראה הפוסט האחרון בסדרה, אלא אם כן אני אחשוב על משהו מעניין שלא כתבתי, או שמישהו יצביע לי על משהו כזה.

מה היה לנו עד כה?

הכרנו מה זה Fluent Syntax. ראינו איך מממשים כזה בעצמנו. ראינו שיש לנו את הפריבילגיה של לשמור Stateים לגבי הפעולות שביצענו, כדי שנציג אותן במידת הצורך. ראינו שאפשר להשמיט את המתודות של Object כדי שלא יפריעו למשתמשים שלנו להשתמש בSyntax שלנו. ראינו שגם לא קשה לממש Fluent Syntax, מאחר ואנחנו מסוגלים לממש מחלקה בודדת.

משהו שאני מרגיש שלא כל כך ברור, הוא מה לעשות כאשר יש לנו פעולה שמתמשכת על גבי כמה מתודות בSyntax:

למשל בטיפ הראשון ראינו משהו כזה:

1
2
3
4
5
6
7
8
9
10
11
12
dataSet.
AddTable("DEPARTMENT").
WithColumn<int>("PK").
MakePrimaryKey().
WithColumn<string>("NAME").
AddTable("EMPLOYER").
WithColumn<string>("NAME").
WithColumn<int>("DEPARTMENT_FK").
RelatedTo("DEPARTMENT").
WithParentKey("PK").
WithChildKey("DEPARTMENT_FK").
Named("EMPLOYER_TO_DEPARTMENT");

זו פעולה בודדת שנפרשת על כמה מתודות, שהרי היא מתרגמת למשהו כזה:

1
2
3
4
5
6
DataRelation employerToDepartment =
new DataRelation("EMPLOYER_TO_DEPARTMENT",
departments.Columns["PK"],
employers.Columns["DEPARTMENT_FK"]);
employers.ParentRelations.Add(employerToDepartment);

אז איך עושים את זה?

קודם כל ניצור את הממשקים המתאימים:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface ITableDefinitionSyntax
{
ITableOrColumnDefinitionSyntax<T> WithColumn<T>(string name);
IRelationSyntaxParentDefinition RelatedTo(string tableName);
}
public interface IRelationSyntaxParentDefinition
{
IRelationSyntaxChildDefinition WithParentKey(string key);
}
public interface IRelationSyntaxChildDefinition
{
IRelationSyntaxNameDefinition WithChildKey(string key);
}
public interface IRelationSyntaxNameDefinition
{
ITableDefinitionSyntax Named(string relationName);
}

כעת נממש אותם בצורה הפשוטה:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
internal class TableDefinitionSyntax :
ITableDefinitionSyntax,
IRelationSyntaxParentDefinition,
IRelationSyntaxChildDefinition,
IRelationSyntaxNameDefinition
{
protected readonly DataTable mTable;
protected DataTable mParentTable;
protected DataColumn mParentKey;
protected DataColumn mChildKey;
public TableDefinitionSyntax(DataTable table)
{
mTable = table;
}
ITableOrColumnDefinitionSyntax<T> ITableDefinitionSyntax.WithColumn<T>(string name)
{
DataColumn column = mTable.Columns.Add(name, typeof(T));
return new TableOrColumnDefinitionSyntax<T>(mTable, column);
}
IRelationSyntaxParentDefinition ITableDefinitionSyntax.RelatedTo(string tableName)
{
mParentTable = mTable.DataSet.Tables[tableName];
return this;
}
IRelationSyntaxChildDefinition IRelationSyntaxParentDefinition.WithParentKey(string key)
{
mParentKey = mParentTable.Columns[key];
return this;
}
IRelationSyntaxNameDefinition IRelationSyntaxChildDefinition.WithChildKey(string key)
{
mChildKey = mTable.Columns[key];
return this;
}
ITableDefinitionSyntax IRelationSyntaxNameDefinition.Named(string relationName)
{
mTable.ParentRelations.Add(relationName,
mParentKey,
mChildKey);
return this;
}
}

הקסם כאן הוא שעד הפונקציה Named, לא עשינו באמת עשינו משהו, אלא רק שמרנו את הדברים בצד.

נשים לב שבOverload של Add, השם של הRelation הוא רשות. נניח והיינו רוצים שהSyntax שלנו יתמוך בשם אופציונאלי. איך נוכל לעשות זאת?

נוסיף Member ששומר את הRelation:

1
protected DataRelation mRelation;

בפונקציה WithChildKey נדאג לשמור אותו בצד אחרי שהוספנו אותו:

1
2
3
4
5
6
7
8
IRelationSyntaxNameDefinition IRelationSyntaxChildDefinition.WithChildKey(string key)
{
mChildKey = mTable.Columns[key];
mRelation = mTable.ParentRelations.Add(mParentKey, mChildKey);
return this;
}

ובפונקציה Named נדאג לשנות לו את השם 😃:

1
2
3
4
5
6
ITableDefinitionSyntax IRelationSyntaxNameDefinition.Named(string relationName)
{
mRelation.RelationName = relationName;
return this;
}

כמובן, כדאי שנאפשר למשתמש לעשות עוד משהו פרט לNamed (שהרי Named זה אופציונאלי):

1
2
3
4
public interface IRelationSyntaxNameDefinition : ITableDefinitionSyntax
{
ITableDefinitionSyntax Named(string relationName);
}

המשך יום צף טוב!

שתף