简体   繁体   English

方法链的最佳实践(“return this”)

[英]Best practice for method chaining (“return this”)

I have an abstract class called DatabaseRow that, after being derived and constructed, is mainly loaded from a Load(object id) method.我有一个名为DatabaseRow的抽象 class ,在派生和构造之后,主要从Load(object id)方法加载。

I have lots of code that creates a new instance of the class, loads it from an ID, then returns the class.我有很多代码可以创建 class 的新实例,从 ID 加载它,然后返回 class。 I'd like to simplify this code into one line of code (just to be neat, there are plenty of classes that will just have lists of properties that return these Loaded instances).我想将此代码简化为一行代码(为了简洁起见,有很多类只有返回这些 Loaded 实例的属性列表)。

There are two ways I can think of doing it, but neither seem 'right' to me.我可以想到两种方法,但对我来说似乎都不“正确”。

1. I could return this; 1.我可以return this; at the end of my Load method and use return new Derived().Load(id);在我的Load方法结束时使用return new Derived().Load(id);

2. I could create a generic method to return a loaded method. 2.我可以创建一个通用方法来返回一个加载的方法。

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

I've seen some other code that uses the same method as number 1 , but I've never seen any experienced developer recommend it, nor have I came across any methods in the .NET framework that do the same thing, so maybe this isn't best practice?我见过一些其他代码使用与数字1相同的方法,但我从未见过任何有经验的开发人员推荐它,我也没有遇到 .NET 框架中做同样事情的任何方法,所以也许这不是最佳实践?

Does anybody know of any other solutions that could be better than both of these?有谁知道任何其他可能比这两个更好的解决方案?

Solution:解决方案:

After reading SirViver's answer and comment, I realised that all the properties being returned need to be cached anyway.在阅读了 SirViver 的回答和评论后,我意识到返回的所有属性无论如何都需要缓存。 The solution was sightly different, but similar to option 2 (that I wouldn't expect anyone to come up with this answer as I didn't explain this part of the design)解决方案明显不同,但类似于选项2 (我不希望有人提出这个答案,因为我没有解释这部分设计)

All these instances will be loaded from a value retrieved from another column in the database (database relationships if you like).所有这些实例都将从数据库中另一列检索到的值加载(如果您愿意,可以使用数据库关系)。 Instead of trying to load the new instance from this value, I made a method to load the instance from the column name and cache the loaded value in a Dictionary.我没有尝试从该值加载新实例,而是创建了一个从列名加载实例并将加载的值缓存在字典中的方法。 This works well as this is one of the primary functions of the DatabaseRow class.这很好用,因为这是DatabaseRow class 的主要功能之一。

    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;
        }
    }

Personally, I think it's bad practice to chain method calls that have actual sideffects on the object instance.就个人而言,我认为链接对 object 实例有实际副作用的方法调用是不好的做法。 To be honest, I think both examples are quite ugly "hacks" whose only purpose is saving two lines of code.老实说,我认为这两个例子都是相当丑陋的“黑客”,其唯一目的是节省两行代码。 I don't think the result is actually more readable either.我不认为结果实际上更具可读性。

If you want a record to be loaded immediately, I'd probably rather supply a constructor variant that takes the ID you load from and make the object auto-populate itself on construction, though when I think about it, I wouldn't bother at all to be honest - cramming more information in a single line does not make for more read- and maintainable code.如果您希望立即加载记录,我可能宁愿提供一个构造函数变体,该变体获取您从中加载的 ID,并使 object 在构造时自动填充,但当我考虑到它时,我不会打扰老实说——在一行中塞进更多信息并不能增加可读性和可维护性的代码。

Number 1 is gaining in popularity in some circles; 1 号在某些圈子中越来越受欢迎; it's often called fluent programming when there's an interface that defines great numbers of these methods and long chains can be assembled.当有一个接口定义了大量这些方法并且可以组装长链时,它通常被称为流利编程 The key to doing this successfully is never to define a method that sometimes returns this , but other times returns null .成功执行此操作的关键是永远不要定义有时返回this ,但有时返回null的方法。 If this is always returned (unless there's an exception) it's perfectly good style.如果this总是返回(除非有例外),这是非常好的风格。

Personally I'm not as fond of solutions like number 2, as it could be said to violate the "one responsibility" principle.就我个人而言,我不喜欢 2 号这样的解决方案,因为它可以说违反了“一个责任”原则。

Option 1 is only acceptable if it is possible to have a row without being loaded.选项 1 仅在可以有一行而不被加载的情况下才可接受。 This is due to the pattern allowing you to do this:这是由于允许您执行此操作的模式:

return new Derived();

Personally I would prefer the static method.我个人更喜欢 static 方法。 But I suspect it is simply a matter of personal preference.但我怀疑这只是个人喜好问题。

As ssg says the other option (lets call it option 3) is to overload the constructor in Derived which would also work, however having lots of constructors can often be confusing as the calling code does not have anything in it which describes what is going on.正如 ssg 所说,另一个选项(让我们称之为选项 3)是重载 Derived 中的构造函数,这也可以工作,但是有很多构造函数通常会令人困惑,因为调用代码中没有任何描述正在发生的事情.

Option 1:选项1:

return new Derived().Load(10);

Option 2:选项 2:

return Derived.Load(10);

Option 3:选项 3:

return new Derived(10);

Option 1 looks like you are getting a superfluous object created.选项 1 看起来您正在创建一个多余的 object。 Option 2 is good because it does what it looks like it is doing.选项 2 很好,因为它做了它看起来正在做的事情。 Option 3 leaves confusion about what it does.选项 3 对它的作用感到困惑。

Although I personally like methods returning this as it allows them to be chained, I think in the .NET framework (up until Linq), this was frowned upon.尽管我个人喜欢返回this的方法,因为它允许将它们链接起来,但我认为在 .NET 框架(直到 Linq)中,这被不赞成。 The reason that pops to mind is this:浮现在脑海的原因是:

Methods either return a result or change the state of the object.方法要么返回结果,要么更改 object 的 state。 Returning this is a bit of both: Changing the state of the object and then returning a "result" - except that result is the modified original object.返回this两者都有一点:更改 object 的 state 然后返回“结果” - 除了结果是修改后的原始 object。 This doesn't fit the expectations of the user.这不符合用户的期望。

What about:关于什么:

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

And use it like this:并像这样使用它:

return new Derived(id);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM