简体   繁体   English

静态工厂方法与公共构造函数

[英]Static factory method vs public constructor

Background: 背景:

Here's the code for what I'm currently working on. 这是我目前正在处理的代码。 First, the base class, which is an account class that holds information about the account and has some methods that for the most part change the values of the class's properties. 首先,基类是一个帐户类,其中包含有关帐户的信息并具有一些方法,这些方法在大多数情况下会更改类的属性的值。

public class Account {
    private string _username; [...]

    public string Username { get { return _username; } } [...]

    public Account() { }

    public Account(string[] args) { [...] }

    public virtual void ChangePassword(string newPassword) { [...] }
}

Then, I have another class for when the account has been created, which I have named ActiveAccount. 然后,我有另一个用于创建帐户的类,我将其命名为ActiveAccount。 This contains most of the logic for the actions I want to use for the account that are only possible once the account has been created. 这包含了我要用于帐户的操作的大多数逻辑,这些逻辑只有在创建帐户后才可能执行。 Some classes need not to be included to explain the question; 无需包括某些类来解释该问题。 use your imagination to assume what those classes may do: 用您的想象力假设这些课程可以做什么:

public class ActiveAccount : Account
{
    private List<Conversation> _conversations; [...]

    public List<Conversation> Conversations { get { return _conversations; } } [...]

    private ActiveAccount() { }

    public static ActiveAccount CreateAccount(Account account)
    {
        // Navigate to URL, input fields, create account, etc.
    }

    public override void ChangePassword(string newPassword)
    {
        // Navigate to URL, input fields, change password, etc.

        // Update property using base method, if no errors.
        base.ChangePassword(newPassword);
    }
}

I've used a static factory method for two reasons. 我使用静态工厂方法有两个原因。 1) I want customiseable and extensible construction of an object (for example, in the future I might have an AccountTemplate from which I provide generic information to create accounts; I can easily create another static factory method overload with an AccountTemplate parameter), and 2) having a parameterless constructor allows me to serialize this object more easily into XML/JSON. 1)我想要一个可自定义和可扩展的对象构造(例如,将来我可能有一个AccountTemplate,可以从中提供通用信息来创建帐户;我可以使用AccountTemplate参数轻松创建另一个静态工厂方法重载),以及2 )具有无参数的构造函数,这使我可以更轻松地将此对象序列化为XML / JSON。

Question: 题:

However, it's come to my attention that I could just as easily have a public constructor that accepts an Account parameter, performs the logic and can be extended with overloads just as easily. 但是,引起我注意的是,我可以很容易地拥有一个接受Account参数,执行逻辑并可以重载进行扩展的公共构造函数。 I can keep my private parameterless constructor to prevent parameterless construction and allow serialization. 我可以保留我的私有无参数构造函数,以防止无参数构造并允许序列化。

I'm quite new to programming. 我是编程新手。 What I'm wondering is if there is a specific reason to use static factory methods instead of public constructors, as explained above. 我想知道的是,是否有特定的原因使用静态工厂方法而不是公共构造函数,如上所述。 And what's the preferred way of doing what I want to do? 做我想做的事的首选方式是什么?

I wouldn't call what you used a static factory. 我不会称您使用的是静态工厂。 In my eyes it's a "named constructor" since it resides in the class itself and just creates an object of that particular class. 在我看来,它是“命名构造函数”,因为它驻留在类本身中,并且仅创建该特定类的对象。

It is often used to make the operation easier to understand, eg compare 它通常用于使操作更易于理解,例如比较

int value = Int32.Parse(someString);
int value = new Int32(someString); // doesn't really exist

The first version makes it clear that it parses the input string, the second is far less verbose. 第一个版本清楚地说明了它解析输入字符串,第二个版本则不那么冗长。

Update: one important difference between constructors and static methods like Int32.Parse is that static methods can chose whether to return null in case an error occured or throw an exception. 更新:构造函数和静态方法(如Int32.Parse )之间的重要区别是,静态方法可以选择是否在发生错误时返回null或引发异常。 A constructor can only throw an exception or - and I wouldn't recommend that - leave the object in some sort of limbo state where it is only half-initialized. 构造函数只能抛出一个异常,或者-我不建议这样做-将对象置于某种状态,在该状态中它仅被半初始化。


A static factory is used to decouple classes, and to make it easier to change the implementation, for example instead of instantiating a database connection using the new operator in your code every time you need a database connection you use a factory method that returns an interface: 静态工厂用于解耦类,并使更改实现更容易,例如,每次需要数据库连接时,都无需使用代码中的new运算符实例化数据库连接,而是使用返回接口的工厂方法:

SqlConnection myConnection = new SqlConnection(connectionString);
IDbConnection myConnection = myFactory.CreateConnection();

The advantage is that by simply changing the CreateConnection method you can make global changes to your entire project, swapping databases servers or even database providers without having to change your code in all the places where you actually use the database connection. 优点是,只需更改CreateConnection方法,即可对整个项目进行全局更改,交换数据库服务器甚至数据库提供程序,而不必在实际使用数据库连接的所有位置上更改代码。

I would advise you to read the .NET constructor guidelines . 我建议您阅读.NET构造函数指南 There are some points that probably leads to choosing a static factory instead of a constructor in your case. 在某些情况下,可能会导致选择静态工厂而不是构造函数。 Namely

Do minimal work in the constructor. 在构造函数中完成最少的工作。 Constructors should not do much work other than to capture the constructor parameters. 除了捕获构造函数参数外,构造函数不应做太多工作。 The cost of any other processing should be delayed until required. 任何其他处理的成本都应延迟到需要时再进行。

and

Consider using a static factory method instead of a constructor if the semantics of the desired operation do not map directly to the construction of a new instance, or if following the constructor design guidelines feels unnatural. 如果所需操作的语义没有直接映射到新实例的构造,或者如果遵循构造函数设计准则感到不自然,请考虑使用静态工厂方法而不是构造函数。

There are my consideration about when you need to prefer a static factory method and when a constructor. 我需要考虑何时需要使用静态工厂方法以及何时使用构造函数。

1) Use a static factory method if you need to do some additional actions/initializations that cannot be done by a constructor. 1)如果需要执行一些构造函数无法完成的其他动作/初始化,请使用静态工厂方法。 For example if you need to publish newly created ActiveAccount object (eg SomePublicList.Add(ActiveAccount); ) then it's a bad practice to publish it from within it's own constructor. 例如,如果您需要发布新创建的ActiveAccount对象(例如SomePublicList.Add(ActiveAccount); ),那么从它自己的构造函数中发布它是一个坏习惯。

2) Think about inheritance. 2)考虑继承。 If you need to create a descendent class (eg NewActiveAccout ) for ActiveAccount then you need to provide a non-private constructor in ActiveAccount . 如果您需要为ActiveAccount创建一个后代类(例如NewActiveAccout ),则需要在ActiveAccount提供一个非私有的构造函数。 Perhaps you need to prefer a constructor to a factory method in that case. 在这种情况下,也许您需要使用构造方法而不是工厂方法。

3) If you need to pass some parameters to the base class ( Account ) constructor then you need to implement a constructor in ActiveAccount because you can't pass parameters to base class constructor from a static factory method. 3)如果需要将一些参数传递给基类( Account )构造函数,则需要在ActiveAccount实现构造函数,因为您无法从静态工厂方法将参数传递给基类构造函数。

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

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