【发布时间】:2010-02-17 06:36:56
【问题描述】:
我将举例说明一个问题。有一个具有流畅接口的基类:
class FluentPerson
{
private string _FirstName = String.Empty;
private string _LastName = String.Empty;
public FluentPerson WithFirstName(string firstName)
{
_FirstName = firstName;
return this;
}
public FluentPerson WithLastName(string lastName)
{
_LastName = lastName;
return this;
}
public override string ToString()
{
return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
}
}
还有一个子类:
class FluentCustomer : FluentPerson
{
private long _Id;
private string _AccountNumber = String.Empty;
public FluentCustomer WithAccountNumber(string accountNumber)
{
_AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(long id)
{
_Id = id;
return this;
}
public override string ToString()
{
return base.ToString() + String.Format(" account number: {0} id: {1}", _AccountNumber, _Id);
}
}
问题是当你调用customer.WithAccountNumber("000").WithFirstName("John").WithLastName("Smith")时你不能在最后添加.WithId(123),因为WithLastName()方法的返回类型是FluentPerson(不是FluentCustomer)。
这个问题通常是如何解决的?
【问题讨论】:
-
有趣的线程!问题和给出的答案,从禁用继承 (Ramesh)、创建将 Person 类型转换为 Customer (Dzimtry) 的扩展方法、Yann 对“基”类的泛型的有趣使用、RichardTallent 将其分解为两个单独的类具有重复字段和 Gorpik 的 cmets :都增加了我的信念,即我应该远离使用流畅的接口进行编程。对我来说,方法链的“美”并不能证明这里提出的“瑜伽代码扭曲”是合理的。但我准备像往常一样“吃我的话”:)
-
@BillW:你是对的。实际上我问了这个问题,因为我已经有一个具有流畅接口的类,我需要实现另一个类,它使用了第一类的很多功能。还有一个要求是不要破坏旧代码。我认为流畅的界面不是一个通用的东西,你可以没有它,但在某些情况下它们真的很方便(不是必需的)。顺便说一句,我也对答案中建议的方法范围感到惊讶。
-
我刚刚探索了下面的解决方案,我认为它归结为这些权衡:1)泛型允许具有继承(并使用受保护的成员),但只允许 2 级继承。如果您的类已经使用泛型,它可能会变得非常混乱。 2)扩展允许有多个继承级别(并且非常干净),但不允许使用受保护的成员。你可能不得不揭露一些事情。 3)组合(而不是继承)提供了更大的灵活性,但可能变得过于冗长(每个派生类都必须委托它继承的所有方法)。
标签: c# inheritance fluent-interface