C#中的Fluent接口
本文关键字:接口 Fluent 中的 | 更新日期: 2023-09-27 17:47:50
我有一个关于流畅接口的问题。
我们有一些对象用作SQL接口的参数对象,下面是一个例子:
using (DatabaseCommand cmd = conn.CreateCommand(
"SELECT A, B, C FROM tablename WHERE ID = :ID",
SqlParameter.Int32(":ID", 1234)))
{
...
}
对于其中的一些参数,我想启用一些专门的选项,但我不想在Int32方法中添加更多的属性(这只是众多方法中的一个),而是想研究流畅的接口。
这里有一个例子,我添加了我正在研究的内容:
SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
.Substitute
.Precision(15)
)
我知道这两个选项对这种类型的参数没有意义,但这不是问题所在。
在上面的情况下,Substitute必须是SqlParameterOption类的静态属性(或者方法,如果我只是添加一些括号的话),而Precision必须是实例方法。
如果我重新订购呢?
SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
.Precision(15)
.Substitute
)
那么Substitute必须是实例属性,Precision必须是静态方法。当然,这不会编译,我不能同时具有相同名称的静态和非静态属性或方法。
我该怎么做?我是不是完全走错了路?
在重读这个问题时,我有一个想法,下面这种不同的语法会更有意义吗?
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute
在这种情况下,这两个方法都是With返回的实例方法,这将是SqlParameter选项的专用类或接口。我不确定我是否要转储。对于部分,因为这将暴露对象的所有方法,而不仅仅是流畅的方法。
建议和一些好的url将是最受欢迎的,我已经搜索了很多例子,但他们倾向于显示这样的例子:
order
.AddFreeShipping()
.IncludeItem(15)
.SuppressTax();
(从本页起)
编辑:回复后跟进发件人@marxidad:
class SqlParameterOption
{
public SqlParameterOption Precision(int p) {/* ... */; return this;}
public SqlParameterOption Substitute() {/* ... */; return this;}
/* ... */
}
/* ... */
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
使用这种方法,With必须获取对象,并将其应用于参数。我对此很满意。
如果我使用我添加的语法作为例子,它会是这样的:
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute());
在这种情况下,With不知道链何时结束,因此每个选项都必须直接应用其效果。
首选项是什么?选项建立了一个稍后必须应用的效果对象,还是每个效果都直接应用其效果?
我的决定:正如@marxidad所说,如果这些变化是不可逆转的,并且可能会发生逆转,那么我会选择建立状态并在某个时候失败(只有一个例外)。
但是,在这种情况下,我将使用一种更简单的方法,直接修改SqlParameter对象。
在这种情况下,我的代码将如下所示:
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute());
编辑:啊,当我只关注一件事时,情况就是这样。
我不能使用这种语法,我将按照@marxidad:的建议使用以下语法
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
当然,原因是将SqlParameter对象作为参数的方法无法处理with返回的对象,因此,尽管SqlParameter的对象构造和设置正确,但它与预期用途不兼容。
SqlParameterOption's
方法都可以是返回相同对象的实例方法:
class SqlParameterOption
{
public SqlParameterOption Precision(int p) {/* ... */; return this;}
public SqlParameterOption Substitute() {/* ... */; return this;}
/* ... */
}
/* ... */
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
回复:建立稍后应用的状态,而不是每次调用都直接应用,如果在这两种情况下都没有真正的无法验证的副作用,那么这无关紧要,取决于您的个人品味。如果每个方法调用都提交了选项,并且您可能希望撤消该选项,那么您可能希望先建立状态,然后应用它。如果参数对象在应用属性时为您在属性之间进行验证,那么最好使用直接应用程序,这样您就可以正确地获得验证反馈。
您可以重载方法。例如,如果它是Substitute()。通常不能同时拥有方法的静态版本和实例版本,但扩展方法可能会有一些用处。。。但是,如果Substitute的两个版本有不同的含义,那么简单地返回不同的类型会更干净,这样Substitute()的两个变体就不会冲突。