我正在尝试实现一个流畅的界面,让我指定一个包含列的表,其中表和列具有属性。我希望能够像这样初始化表类:
var t = TableBuilder.Create()
.WithName("test")
.WithColumn("col1").WithType("Int32")
.WithColumn("col2").WithType("String")
.WithColumn("col3");
我提出了一个有效的解决方案。我的问题是,可以简化实施还是采取完全不同的方法?我已经在类似情况下看到了扩展方法的使用,但我不知道他们是否会帮助我或者在这种情况下如何使用它们。
以下是代码(下面有一些评论):
interface ITable
{
ITable WithName(string tableName);
ITableAndColum<ITable, IColumn> WithColumn(string columnName);
}
interface IColumn
{
IColumn WithType(string typeName);
}
interface ITableAndColum<TTable, TColumn>
where TTable : ITable
where TColumn : IColumn
{
ITableAndColum<ITable, IColumn> WithColumn(string columnName);
ITableAndColum<ITable, IColumn> WithType(string typeName);
}
class TableAndColumn : ITableAndColum<ITable, IColumn>
{
public ITable Table { get; set; }
public IColumn Column { get; set; }
public ITableAndColum<ITable, IColumn> WithColumn(string columnName)
{
return Table.WithColumn(columnName);
}
public ITableAndColum<ITable, IColumn> WithType(string typeName)
{
Column.WithType(typeName);
return this;
}
public override string ToString()
{
return Table.ToString();
}
}
class Column : IColumn
{
public string ColumnName { get; set; }
public string TypeName { get; set; }
public IColumn WithType(string typeName)
{
TypeName = typeName;
return this;
}
}
class TableBuilder : ITable
{
public string TableName { get; set; }
List<Column> Columns;
TableBuilder() { Columns = new List<Column>(); }
public static ITable Create() { return new TableBuilder(); }
public ITable WithName(string tableName)
{
TableName = tableName;
return this;
}
public ITableAndColum<ITable, IColumn> WithColumn(string columnName)
{
Column thisColumn = new Column() { ColumnName = columnName };
Columns.Add(thisColumn);
return new TableAndColumn() { Table = this, Column = thisColumn };
}
public override string ToString()
{
return TableName + "(" + string.Join(",", Columns.Select(c => (c.TypeName != null ? c.TypeName + " " : "") + c.ColumnName)) + ")";
}
}
class Example
{
public Example()
{
var t = TableBuilder.Create()
.WithName("test")
.WithColumn("col1").WithType("Int32")
.WithColumn("col2").WithType("String")
.WithColumn("col3");
var tdef = t.ToString();
}
}
有两个接口ITable
和IColumn
,其中包含Table
和Colum
实现。他们揭示了特定于其类型的适当方法。第三个接口ITableAndColumn
组合了其他接口,它的实现TableAndColumn
包含对Table实例和Column实例的引用。接口公开了ITable
和IColumn
的选定方法,并调用适当的实例。
这种方法是否复杂?扩展方法是否会以任何方式解决这个问题?
答案 0 :(得分:2)
我不是制作TableAndColumn
的忠实粉丝。对我而言似乎错了。他们是不同的实体。我已经从KendoUI中找到了一个流畅的风格页面:
TableBuilder.Create()
.WithName("test")
.WithColumn(c => c.WithName("col1").WithType("Int32"))
.WithColumn(c => c.WithName("col2").WithType("String"))
.WithColumn(c => c.WithName("col3"));
请注意我们如何通过lambda配置列。这使我们能够正确地约束IColumn
可以暴露的内容。
当然,您可以将其更改为:WithColumn("col1", c => c.WithType("Int32"))
和重载.WithColumn("col3")
。
实现:
interface ITable
{
ITable WithColumn(Action<IColumn> c);
ITable WithName(string tableName);
}
interface IColumn
{
IColumn WithName(string columnName);
IColumn WithType(string typeName);
}
class TableBuilder : ITable
{
public string TableName { get; set; }
List<Column> Columns = new List<Column>();
public static ITable Create() { return new TableBuilder(); }
public ITable WithName(string tableName)
{
TableName = tableName;
return this;
}
public ITable WithColumn(Action<IColumn> c)
{
Column thisColumn = new Column();
c(thisColumn);
Columns.Add(thisColumn);
return this;
}
}
class Column : IColumn
{
public string ColumnName { get; set; }
public string TypeName { get; set; }
public IColumn WithName(string columnName)
{
ColumnName = columnName;
return this;
}
public IColumn WithType(string typeName)
{
TypeName = typeName;
return this;
}
}