方法链的最佳实践(“返回此”)

时间:2011-06-01 11:39:16

标签: c# .net return-value

我有一个名为DatabaseRow的抽象类,在派生和构造之后,主要从Load(object id)方法加载。

我有很多代码可以创建类的新实例,从ID加载它,然后返回类。我想将这段代码简化为一行代码(只是为了整洁,有很多类只有具有返回这些Loaded实例的属性列表)。

我可以通过两种方式来做这件事,但对我来说似乎都不对。

1。我可以在return this;方法结束后Load使用return new Derived().Load(id);

2. 我可以创建一个通用方法来返回一个加载的方法。

public static T LoadRow<T>(object id) where T : DatabaseRow, new()
{
    T row = new T();
    row.Load(id);
    return row;
}

我见过其他一些使用与 1 相同的方法的代码,但我从未见过任何有经验的开发人员推荐它,也没有遇到.NET框架中的任何方法做同样的事情,所以也许这不是最佳做法?

是否有人知道其他任何可能比这两种解决方案都更好的解决方案?

解决方案:

在阅读SirViver的回答和评论之后,我意识到所有返回的属性都需要缓存。解决方案有点不同,但类似于选项 2 (我不希望任何人提出这个答案,因为我没有解释这部分设计)

所有这些实例都将从数据库中另一列检索的值(如果您愿意,数据库关系)中加载。我没有尝试从这个值加载新实例,而是创建了一个从列名加载实例并将加载的值缓存到Dictionary中的方法。这很有效,因为这是DatabaseRow类的主要功能之一。

    private Dictionary<string, DatabaseRow> linkedRows;

    protected T GetLinkedRow<T>(string key) where T : DatabaseRow, new()
    {
        if (linkedRows.ContainsKey(key)) return (T)linkedRows[key];
        else
        {
            T row = new T();
            row.Load(this[key]);
            linkedRows.Add(key, row);
            return row;
        }
    }

4 个答案:

答案 0 :(得分:3)

就个人而言,我认为链接对象实例具有实际副作用的方法调用是不好的做法。说实话,我认为这两个例子都是非常丑陋的“黑客”,其唯一目的是节省两行代码。我不认为结果实际上更具可读性。

如果你想立即加载一条记录,我可能宁愿提供一个构造函数变体来获取你加载的ID,并使该对象在构造时自动填充,但是当我想到它时,我不会'实在是太麻烦了 - 在一行中填充更多信息并不能提供更多可读和可维护的代码。

答案 1 :(得分:2)

第一名在某些圈子中越来越受欢迎;当有一个接口定义了大量的这些方法并且可以组装长链时,它通常被称为流畅的编程。成功完成此操作的关键是永远不要定义有时返回this的方法,但有时会返回null。如果总是返回this(除非有例外),那就是非常好的风格。

我个人并不喜欢像2号这样的解决方案,因为可以说它违反了“一个责任”的原则。

答案 2 :(得分:1)

只有在没有加载的情况下才能使用选项1。这是由于允许您执行此操作的模式:

return new Derived();

我个人更喜欢静态方法。但我怀疑这只是个人偏好的问题。

正如ssg所说的另一个选项(让我们称之为选项3)是重载Derived中的构造函数也可以工作,但是有很多构造函数通常会让人困惑,因为调用代码中没有任何东西可以解释什么正在继续。

选项1:

return new Derived().Load(10);

选项2:

return Derived.Load(10);

选项3:

return new Derived(10);

选项1看起来像是在创建一个多余的对象。选项2很好,因为它做了它看起来正在做的事情。备选方案3对它的作用感到困惑。

答案 3 :(得分:0)

虽然我个人喜欢返回this的方法,因为它允许它们被链接,但我认为在.NET框架中(直到Linq),这是不受欢迎的。想到这一点的原因是:

方法返回结果或更改对象的状态。返回this有两点:更改对象的状态然后返回“结果” - 除了结果是修改后的原始对象。这不符合用户的期望。

怎么样:

public class Derived : DatabaseRow
{
    public Derived(object id):
    {
        Load(id);
    }
}

并像这样使用它:

return new Derived(id);