2009-05-18 93 views
11

什麼是優點,什麼時候適合使用靜態構造函數?爲什麼要使用Create方法而不是使用「new」?

public class MyClass 
{ 
    protected MyClass() 
    { 
    } 

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

,然後通過

MyClass myClass = MyClass.Create(); 

創建類的實例,而不是僅僅有一個公共的構造和使用

MyClass myClass = new MyClass(); 

創建對象,我可以看到第一種方法是有用如果Create方法返回類實現的接口的實例...它將強制調用者創建接口的實例而不是特定的類型。

回答

15

這是工廠模式,它通常可以用來產生一個子類,但允許參數以靜態方法確定哪一個。

它也可以用於新的對象不總是需要的,例如在一個池實現中。

如果對象的所有實例需要在創建時進行緩存或註冊,也可以使用它。這確保客戶不會忘記這樣做。

當然,它是Singleton模式的組成部分。

1

此模式通常用於Singleton pattern。對於只有在程序生命期間僅實例化一次的類的類或外觀時,這通常會因爲對象將使用的資源而變得很有用。

How to in C#

+2

單例模式將返回對同一對象的引用,而工廠模式創建可能共享數據的多個實例。 – 2009-05-18 03:21:52

+1

正如BillyONeal提到的,這不是Singleton模式; Singleton強制只創建一個類的一個實例。什麼時候你可能想要使用Singleton模式的一個很好的例子是隻有一個應該存在的設置類。 – 2009-05-18 03:46:19

+0

雖然你們兩個都是對的,他的代碼並不一定能傳達一個單數,但請記住,他最初的問題是圍繞使用工廠和單件使用的*靜態構造*。 – 2009-05-18 14:40:06

1

有你可以這樣做,例如總是從一個固定的對象池(包括Singleton對象)返回實例各種原因,或者像你說的,返回一個接口的實例。

但是,如果你沒有明確的理由去做,不要。

2

在多個類實例共享同一個初始化數據塊的情況下可能很有用 - 這是OOP工廠模式。

一個例子是連接到數據庫的類 - 只需要一個連接,並且可以被類的所有實例共享。

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

Billy3

+0

這不需要工廠方法。它可以用一個靜態連接變量來完成。 – 2009-05-18 03:35:30

+0

是的。但這不是OP的代碼寫入的方式。 – 2009-05-18 22:38:53

1

這種做法只是常用用於單身,否則這種做法是非正統的。直到你明白它想要做什麼之前不要使用它。

+0

感謝喬恩,我知道如何,何時以及爲什麼要使用單身人士,但我敢肯定我看過使用這個不是單身人士的代碼示例......他們當然可能是錯的,這就是爲什麼我問這個問題的原因:-) – 2009-05-18 03:25:00

+0

不要使用什麼?單身人士或靜態構造函數創建模式。我同意前者(避免單身人士),否則會不同意。建造者/工廠模式是相當標準的,並且OP在詢問爲什麼要理解模式的使用。 – 2009-05-18 22:12:43

1

如果你使用私有構造函數,這是迫使MyClass成爲最終的好方法。這種方式不能創建子類,因爲它們的構造函數不能訪問超類的構造函數。

另一個優點是當你有一個參數的構造函數。然後,你可以用模擬命名參數命名創建:

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

現在比較new MyClass(5)MyClass.createWithDays(5)

8

這不是單...創建將每次返回相同的情況下,如果它是。

這是一種工廠模式。我通常會做到這一點與接口不是類,所以我要在這裏舒展,而是一個人爲的例子是:

public static MyClass Create() 
{ 
    if(OS == Windows) 
     return new MyDerivedClassForWindows(); 
    else if(OS == Linux) 
     return new MyDerivedClassForLinux(); 
    etc.... 
} 
1
從當它是一個單身,有一個「靜態工廠方法」,如 MyClass.Create可以

除了如果執行MyClass.Create的人可能想要返回MyClass的子類...例如在測試過程中它可能會返回MyClassWithExtraTestingFunctionality子類的實例...或者根據配置選項,MyClassBeingRemotedOverTheNetwork子類的實例。

0

當你想要框架,類或其他一些配置來確定WHERE時,這也是常用的e對象實際上將被創建。當您使用新的構造函數方法時,它是在本地創建的。如果使用這種方法,它可能通過服務呼叫遠程創建並返回等。這是Rocky Lhotka在CSLA framework中採用的方法。

1

許多其他答案已經涵蓋了這個想法可能有用的特定場合。封裝實例創建的想法被用在許多IoC框架中,比如Spring,Castle等等。這個想法是,通過集中創建實例,您可以自定義應用程序的配置以使用不同的對象集合。一個常見的例子是日誌。通過更改配置,您可以告訴記錄器工廠根據情況生成不同日誌類的實例。

如果應用了這個想法,可能會導致非常鬆散的耦合系統,這可能會在部署後甚至在運行時輕易更改。但是,隨着您擁有另一個間接級別,複雜性會增加。

3

另一個由Guid.NewGuid()靜態方法演示的原因是,如果類型是一個結構體。在這種情況下,CLR要求默認無參數構造函數創建一個新實例,並將所有字段初始化爲默認值。在Guid的情況下,這意味着:

Guid g = new Guid();

將是Guid.Empty。顯然,你希望能夠創建一個隨機化的新Guid,所以Guid.NewGuid()方法就是一種方法。

1

靜態構造函數也是給你的構造函數更多顯式名稱的好方法。 默認參數

例如:Myclass.create();也可以是有用的。 這一翻譯新MYCLASS的(defaultParam1,defaultParam2 ...)

約書亞布洛赫關於它的effective Java(第1項)

4

您已經張貼不會真的有過使用普通的任何好處的具體例子會談構造函數。有兩種常見模式,但是,它使用這樣的方法,得到的對象:

Singleton模式

的單例模式可以在需要時,以防止一個對象的多個實例可以使用正在創建,但仍然希望利用類的面向對象方面(例如,字段,屬性,無參數方法)。例如:

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

你是對的。這不是一個單例模式。這是一種工廠模式。

使用創建的(),而不是新的給了允許你給有意義的名稱方法從而使用戶更清晰

藉此例如:

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. 我們可以返回一個空的對象,這是不可能的構造做
  2. 如果有很多不同的方法來創建對象,它可以讓您有機會提供更有意義的函數名稱。在示例中,您有User.CreateByCredentials(字符串用戶名,字符串密碼)& User.CreateById(int id)。您可以使用構造函數重載完成相同的功能,但很少有相同的清晰度。
0

而且這可能會在延遲加載的情況下使用。除非需要,否則,由於某些原因,您希望該對象位於其中,但不希望執行實際構造函數中涉及的所有繁重工作。因此,您可以創建一個單獨的方法創建並在您準備好進行繁重工作時調用它。

而且@Rashmi潘迪特寫道:

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

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

你的迴應,你就不能使用,而不是創建兩個不同的創建方法與不同的方法簽名的重載構造?

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; } 
    } 
} 
相關問題