为什么要使用Create方法而不是使用“new”?

时间:2009-05-18 03:10:26

标签: c# constructor

有什么优点,何时使用静态构造函数是合适的?

public class MyClass
{
    protected MyClass()
    {
    }

    public static MyClass Create()
    {
        return new MyClass();
    }
}

然后通过

创建一个类的实例
MyClass myClass = MyClass.Create();

而不是只使用公共构造函数并使用

创建对象
MyClass myClass = new MyClass();

如果Create方法返回类实现的接口实例,我可以看到第一种方法很有用......它会强制调用者创建接口的实例而不是特定的类型。

17 个答案:

答案 0 :(得分:15)

这是工厂模式,它通常可用于生成子类,但允许静态方法的参数确定哪一个。

如果不总是需要新对象,也可以使用它,例如在池实现中。

如果对象的所有实例都需要在创建时进行高速缓存或以其他方式注册,也可以使用它。这可以确保客户不会忘记这样做。

当然,它是Singleton模式的一部分。

答案 1 :(得分:8)

这不是单身人士......每次创建都会返回相同的实例。

这是工厂模式。我通常用接口而不是类来做这个,所以我必须在这里伸展,但一个人为的例子是:

public static MyClass Create()
{
    if(OS == Windows)
        return new MyDerivedClassForWindows();
    else if(OS == Linux)
        return new MyDerivedClassForLinux();
    etc....
}

答案 2 :(得分:4)

您发布的特定示例与使用普通构造函数相比没有任何优势。但是,有两种常见的模式,它们使用这样的方法来生成一个对象:

单身人士模式

当您想要防止创建对象的多个实例但仍希望利用类的面向对象方面(例如,字段,属性,无参数方法)时,可以使用单例模式。例如:

public class MySingletonClass
{
    private MySingletonClass currentInstance = null;

    public MySingletonClass CreateInstance()
    {
         if (currentInstance == null)
         {
              currentInstance = new MySingletonClass();
         }
         else
         {
              return currentInstance;
         }
    }
}

工厂模式

工厂模式是抽象具体课程创作的绝佳机会;例如,让我们假设你有一些XML,并且根据你在XML中看到的节点(NodeA,NodeB或NodeC),你有一个不同的类来处理它。例如:

public class MyXmlProcessorFactory
{
    public static IMyXmlProcessor GetMyXmlProcessor(XmlDocument document)
    {
         XmlNode rootNode = document.DocumentElement;

         if (rootNode.SelectSingleNode("NodeA") != null)
         {
              return new NodeAMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeB") != null)
         {
              return new NodeBMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeC") != null)
         {
              return new NodeCMyXmlProcessor();
         }
         else
         {
              return new DefaultMyXmlProcessor();
         }
    }
}

答案 3 :(得分:3)

Guid.NewGuid()静态方法证明的另一个原因是类型是结构。在这种情况下,CLR要求默认的无参数构造函数创建一个新实例,其中所有字段都初始化为默认值。在Guid的情况下,这意味着:

Guid g = new Guid();

将是Guid.Empty。显然你希望能够创建一个随机化的新Guid,因此Guid.NewGuid()方法就是这样做的。

答案 4 :(得分:3)

你是对的。这不是Singleton模式。这是一种工厂模式。

使用Create()代替new give,可以为方法提供有意义的名称,从而使用户更加清晰

以此为例:

public class User
{
    public int id;
    public string userName;
    public string password;
    public string role;

    private User() { }

    public static User CreateByCredentials(string uid, string pwd)
    {
        User user = new User();
        user.userName = uid;
        user.password = pwd;
        return user;
    }

    public static User CreateById(int id)
    {
        User user = new User();
        user.id = id;
        return user;
    }

}

这种方法有两个好处:

  1. 我们可以返回一个null对象,这对于构造函数是不可能的(这在所有情况下都可能有用,也可能没用。)
  2. 如果有很多不同的方法来创建对象,它会让您有机会提供更有意义的函数名称。在示例中,您有User.CreateByCredentials(字符串用户名,字符串密码)& User.CreateById(int id)。您可以使用构造函数重载来完成相同的功能,但很少具有相同的清晰度。

答案 5 :(得分:2)

在多个类实例共享同一块初始化数据的情况下,这可能很有用 - 这是OOP工厂模式。

一个示例是连接到数据库的类 - 只需要一个连接,并且可以由该类的所有实例共享。

http://en.wikipedia.org/wiki/Factory_pattern

Billy3

答案 6 :(得分:2)

更正式地说,它通常被称为Replace Constructor with Factory Method

  

创建对象时,您希望做的不仅仅是简单构造。

即。通过使用工厂方法,您可以更加明确,并通过简单的构造函数为代码提供更多创建选项。

我推荐这本书Refactoring: Improving the Design of Existing Code (Fowler)

答案 7 :(得分:1)

有多种原因可以执行此操作,例如始终从固定对象池(包括Singleton对象)返回实例,或者如您所说,返回接口实例。

但是如果你没有明确的理由去做,那就不要。

答案 8 :(得分:1)

这种方法只是通常用于单身人士,否则这种做法是非正统的。在你明白它想要做什么之前不要使用。

答案 9 :(得分:1)

如果您使用私有构造函数,这是强制MyClass成为最终版的好方法。这样就无法创建子类,因为它们的构造函数无法访问super的构造函数。

另一个优点是当你有一个构造函数的参数。然后,您可以使用模拟命名参数来命名创建:

public static MyClass createWithDays(int days) {
...
}

现在将new MyClass(5)MyClass.createWithDays(5)

进行比较

答案 10 :(得分:1)

除了它是一个单例之外,如果实现MyClass.Create的人可能想要返回MyClass.Create的子类,那么拥有一个“静态工厂方法”(例如MyClass)会很有用。 ..例如,在测试期间,它可以返回MyClassWithExtraTestingFunctionality子类的实例...或者,根据配置选项,MyClassBeingRemotedOverTheNetwork子类的实例...

答案 11 :(得分:1)

此模式通常用于Singleton pattern。当一个类的类或外观只能在程序生命期间实例化一次时,它很有用,通常是因为该对象将使用的资源。

How to in C#

答案 12 :(得分:1)

许多其他答案涵盖了这个想法可能有用的特定场合。封装实例创建的想法在许多IoC框架中使用,例如Spring,Castle等。我们的想法是,通过集中实例创建,您可以自定义应用程序的配置以使用不同的对象集。一个常见的例子是记录。通过更改配置,您可以根据具体情况告诉记录器工厂生成不同的日志记录类实例。

如果应用这个想法可能导致非常松散耦合的系统,可能在部署后甚至在运行时很容易更改。但是,随着您拥有另一个间接层,复杂性也会增加。

答案 13 :(得分:1)

静态构造函数也是为构造函数提供更明确名称的好方法。 它对默认参数

也很有用

ex:Myclass.create(); intec of new Myclass(defaultParam1,defaultParam2 ...)

Joshua Bloch在effective Java(第1项)

中谈到了这个问题

答案 14 :(得分:0)

请注意,在使用构造函数方法时,您只能使用构造函数初始化。

    public void Example()
    {
        var person = new Person
                         {
                             GivenName = "John",
                             FamilyName = "Smith",
                             Address = new Address
                                           {
                                               Street = "Wallace",
                                               Number = 12
                                           },
                             PhoneNumbers = new List<PhoneNumber>
                                                {
                                                    new PhoneNumber
                                                        {
                                                            Number = 1234234,
                                                            AreaCode = 02
                                                        },
                                                    new PhoneNumber
                                                        {
                                                            Number = 1234234, AreaCode = 02
                                                        }
                                                }
                         };
    }

    internal class PhoneNumber
    {
        public int AreaCode { get; set; }

        public int Number { get; set; }
    }

    internal class Address
    {
        public int Number { get; set; }

        public string Street { get; set; }
    }

    internal class Person
    {
        public Address Address { get; set; }

        public string GivenName { get; set; }

        public string FamilyName { get; set; }

        public List<PhoneNumber> PhoneNumbers { get; set; }
    }
}

答案 15 :(得分:0)

这也适用于延迟加载的情况。你希望对象出于某种原因出现在哪里,但除非需要,否则不要做真正构造函数中涉及的所有繁重工作。所以你创建一个单独的方法创建并在你准备好繁重的时候调用它。

@Rashmi Pandit也写道:

   public static User CreateByCredentials(string uid, string pwd)
    {
       ....
    }

    public static User CreateById(int id)
    {
    ...
    }

对于您的回复,您不能仅使用具有不同方法签名的重载构造函数而不是创建两个不同的创建方法吗?

答案 16 :(得分:0)

当您希望框架,类或其他配置确定实际创建对象的WHERE时,也常用此方法。使用新的构造函数方法时,它是在本地创建的。如果您使用这种方法,它可能通过服务调用远程创建并返回,等等。这是Rocky Lhotka在CSLA framework中采用的方法。