Was nützt es, den Konstruktor in einer Klasse privat zu machen?

134

Warum sollten wir den Konstruktor im Unterricht privat machen? Da der Konstruktor immer öffentlich sein muss.

Giri
quelle

Antworten:

129

Einige Gründe, aus denen Sie möglicherweise einen privaten Konstruktor benötigen:

  1. Auf den Konstruktor kann nur über die statische Factory-Methode innerhalb der Klasse selbst zugegriffen werden . Singleton kann auch zu dieser Kategorie gehören.
  2. Eine Utility-Klasse , die nur statische Methoden enthält.
Nanda
quelle
9
Ich hätte mir nicht einmal die Mühe gemacht, einen privaten Konstruktor für eine Utility-Klasse zu erstellen.
Petesh
16
@Patesh: Das ist deine Entscheidung. Andere und ich würden lieber eine Instanziierung der Utility-Klasse verhindern, als einen privaten Konstruktor mit einer Zeile wegzulassen.
Nanda
1
In einigen Programmiersprachen (insbesondere Java) wird auch die Vererbung verhindert
dfa
9
@dfa: Um Vererbung zu verhindern, müssen Sie finalauf Klassenebene setzen. Das Setzen eines privaten Konstruktors ist aus diesem Grund so gut wie nutzlos.
Nanda
3
@ Will: Nicht wenn Sie Reflexion verwenden. Das Deklarieren von Konstruktoren als privat soll die Instanziierung verhindern (außer Reflexion), aber das Verhindern von Unterklassen ist ein Nebeneffekt, nicht die Absicht. Das geeignete Werkzeug hierfür ist das Deklarieren der Klasse final. Dies hat Sun für die String-Klasse getan und einen vernünftigen Teil der API, der nicht erweitert werden sollte.
BobMcGee
96

Durch die Bereitstellung eines privaten Konstruktors verhindern Sie, dass Klasseninstanzen an einem anderen Ort als dieser Klasse erstellt werden. Es gibt mehrere Anwendungsfälle für die Bereitstellung eines solchen Konstruktors.

A. Ihre Klasseninstanzen werden in einer staticMethode erstellt. Die staticMethode wird dann als deklariert public.

class MyClass()
{
private:
  MyClass() { }

public:
  static MyClass * CreateInstance() { return new MyClass(); }
};

B. Ihre Klasse ist ein Singleton . Dies bedeutet, dass nicht mehr als eine Instanz Ihrer Klasse im Programm vorhanden ist.

class MyClass()
{
private:
  MyClass() { }

public:
  MyClass & Instance()
  {
    static MyClass * aGlobalInst = new MyClass();
    return *aGlobalInst;
  }
};

C. (Gilt nur für den kommenden C ++ 0x-Standard) Sie haben mehrere Konstruktoren. Einige von ihnen sind deklariert public, andere private. Um die Codegröße zu reduzieren, rufen öffentliche Konstruktoren private Konstruktoren auf, die wiederum die ganze Arbeit erledigen. Ihre publicKonstruktoren werden daher als delegierende Konstruktoren bezeichnet:

class MyClass
{
public:
  MyClass() : MyClass(2010, 1, 1) { }

private:
  MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};

D. Sie möchten das Kopieren von Objekten einschränken (z. B. aufgrund der Verwendung einer gemeinsam genutzten Ressource):

class MyClass
{
  SharedResource * myResource;

private:
  MyClass(const MyClass & theOriginal) { }
};

E. Ihre Klasse ist eine Utility-Klasse . Das heißt, es enthält nur staticMitglieder. In diesem Fall darf niemals eine Objektinstanz im Programm erstellt werden.

Kerido
quelle
3
In den meisten Fällen möchten Sie das Kopieren von Objekten verhindern. Sie würden also keine Implementierung für den Konstruktor für private Kopien bereitstellen.
Braten
aus dem Google C ++ - Styleguide (ein weiteres Beispiel, das nicht in der Liste enthalten ist, aber häufig verwendet wird) -> Wenn Sie im Konstruktor arbeiten müssen, "betrachten Sie eine Factory-Funktion [und machen Sie den Konstruktor privat]" (Text in eckigen Klammern wird von mir geschrieben )
Trevor Boyd Smith
12

Eine "Hintertür" verlassen, die es einer anderen Freundklasse / Funktion ermöglicht, ein Objekt auf eine Weise zu konstruieren, die dem Benutzer verboten ist. Ein Beispiel, das mir in den Sinn kommt, wäre ein Container, der einen Iterator (C ++) erstellt:

Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
//     and Container is a friend of Iterator.
Emile Cormier
quelle
Ist das anders genug, Terry? ;)
Emile Cormier
Gute Antwort. Warum nicht die Reflexion erwähnen, da dies ein Weg ist, um etwas zu erreichen, was der Benutzer nicht kann?
BobMcGee
@ Bob: Du musst mich darüber aufklären, da ich hauptsächlich ein C ++ - Typ bin und Reflexion nicht wirklich im C ++ - Vokabular enthalten ist. ;)
Emile Cormier
3
Niemand wird dies lesen, aber hier ist es: Ich wurde ein paar Mal in diesem Fall abgelehnt. Nicht verärgert oder so, aber (um zu lernen) möchte ich wissen, warum das schlecht ist? Wie sonst könnte ein Iterator mit den Daten erstellt werden, die er für den Zugriff auf die Daten eines Containers benötigt?
Emile Cormier
2
@EmileCormier, ich denke, Sie wurden zu Unrecht herabgestimmt, weil den Leuten, die C ++ lernen, immer wieder gesagt wird: "Vermeiden Sie Erklärungen von Freunden". Dieser Rat scheint sich an unerfahrene C ++ - Programmierer zu richten, die ihn sonst verwenden könnten, friendwenn dies nicht gerechtfertigt ist - und es gibt viele Fälle, in denen dies eine schlechte Idee ist. Leider wurde die Nachricht zu gut aufgenommen, und viele Entwickler lernen die Sprache nie gut genug, um zu verstehen, dass die gelegentliche Verwendung friendnicht nur akzeptabel, sondern auch vorzuziehen ist . Ihr Beispiel war genau so ein Fall. Absichtliche starke Kopplung ist kein Verbrechen, sondern eine Entwurfsentscheidung.
Evadeflow
10

Jeder steckt in der Singleton-Sache fest, wow.

Andere Dinge:

  • Verhindern Sie, dass Personen Ihre Klasse auf dem Stapel erstellen. Erstellen Sie private Konstruktoren und geben Sie Zeiger nur über eine Factory-Methode zurück.
  • Verhindern, dass Kopien der Klasse erstellt werden (Konstruktor für private Kopien)
Terry Mahaffey
quelle
8

Dies kann für einen Konstruktor sehr nützlich sein, der allgemeinen Code enthält. Private Konstruktoren können von anderen Konstruktoren mit 'this (...);' aufgerufen werden. Notation. Indem Sie den allgemeinen Initialisierungscode in einem privaten (oder geschützten) Konstruktor erstellen, machen Sie auch explizit klar, dass er nur während der Erstellung aufgerufen wird, was nicht der Fall ist, wenn es sich lediglich um eine Methode handelt:

public class Point {
   public Point() {
     this(0,0); // call common constructor
   }
   private Point(int x,int y) {
     m_x = x; m_y = y;
   }
};
Wille
quelle
3

In einigen Fällen möchten Sie möglicherweise keinen öffentlichen Konstruktor verwenden. Zum Beispiel, wenn Sie eine Singleton-Klasse möchten.

Wenn Sie eine Assembly schreiben, die von Drittanbietern verwendet wird, gibt es möglicherweise eine Reihe interner Klassen, die nur von Ihrer Assembly erstellt und nicht von Benutzern Ihrer Assembly instanziiert werden sollen.

Kane
quelle
3

Dadurch wird sichergestellt, dass Sie (die Klasse mit privatem Konstruktor) steuern, wie der Konstruktor aufgerufen wird.

Ein Beispiel: Eine statische Factory-Methode für die Klasse kann Objekte zurückgeben, wenn die Factory-Methode sie zuweist (z. B. eine Singleton-Factory).

Preet Sangha
quelle
@Skilldrick: Ein Beispiel wäre, dass Sie erzwingen können, dass einer Klasse nur ein Heap zugewiesen wird.
Dirk
@dirk Ich habe meinen Kommentar gelöscht, da er nicht mehr relevant ist.
Skilldrick
3

Wir können auch einen privaten Konstruktor haben, um die Erstellung des Objekts nur durch eine bestimmte Klasse durchzuführen (aus Sicherheitsgründen).

Eine Möglichkeit, dies zu tun, besteht darin, eine Freundesklasse zu haben.

C ++ Beispiel:

class ClientClass;
class SecureClass 
{
  private:
    SecureClass();   // Constructor is private.
    friend class ClientClass;  // All methods in 
                               //ClientClass have access to private
                               // &   protected methods of SecureClass.
};

class ClientClass
{
public:
    ClientClass();
    SecureClass* CreateSecureClass()
     { 
           return (new SecureClass());  // we can access 
                                        // constructor of 
                                        // SecureClass as 
                                        // ClientClass is friend 
                                        // of SecureClass.
     }
};

Hinweis: Hinweis: Nur ClientClass (da es mit SecureClass befreundet ist) kann den Konstruktor von SecureClass aufrufen.

vijayNidumolu
quelle
2

Wenn Sie nicht möchten, dass Benutzer Instanzen dieser Klasse erstellen oder eine Klasse erstellen, die diese Klasse erbt, wie z. B. die java.lang.mathgesamte Funktion in diesem Paket static. Alle Funktionen können aufgerufen werden, ohne eine Instanz von zu erstellen. Daher mathwird der Konstruktor als statisch angekündigt .

Shinxg
quelle
1

Wenn es privat ist, können Sie es nicht aufrufen ==> Sie können die Klasse nicht instanziieren. In einigen Fällen nützlich, wie ein Singleton.

Es gibt eine Diskussion und einige weitere Beispiele hier .

Seth
quelle
1

Ich habe eine Frage von Ihnen gesehen, die sich mit demselben Thema befasst.

Wenn Sie den anderen nicht erlauben möchten, Instanzen zu erstellen, halten Sie den Konstruktor in einem begrenzten Bereich. Die praktische Anwendung (ein Beispiel) ist das Singleton-Muster.

Chathuranga Chandrasekara
quelle
1

Sie sollten den Konstruktor nicht privat machen. Zeitraum. Machen Sie es geschützt, damit Sie die Klasse bei Bedarf erweitern können.

Edit: Ich stehe dazu, egal wie viele Downvotes du darauf wirfst. Sie schneiden das Potenzial für zukünftige Entwicklungen des Codes ab. Wenn andere Benutzer oder Programmierer wirklich entschlossen sind, die Klasse zu erweitern, ändern sie einfach den Konstruktor in Quell- oder Bytecode-Schutz. Sie werden nichts anderes erreicht haben, als ihr Leben ein wenig schwieriger zu machen. Fügen Sie eine Warnung in die Kommentare Ihres Konstruktors ein und belassen Sie sie dabei.

Wenn es sich um eine Utility-Klasse handelt, besteht die einfachere, korrektere und elegantere Lösung darin, die gesamte Klasse als "statisch endgültig" zu markieren, um eine Erweiterung zu verhindern. Es nützt nichts, den Konstruktor nur als privat zu markieren. Ein wirklich entschlossener Benutzer kann immer Reflexion verwenden, um den Konstruktor zu erhalten.

Gültige Verwendungen:

  • Eine gute Verwendung eines protected Konstruktors besteht darin, die Verwendung statischer Factory-Methoden zu erzwingen, mit denen Sie die Instanziierung einschränken oder teure Ressourcen (DB-Verbindungen, native Ressourcen) bündeln und wiederverwenden können.
  • Singletons (normalerweise keine gute Übung, aber manchmal notwendig)
BobMcGee
quelle
2
Nach meiner Erfahrung gibt es keine absoluten Wahrheiten, sogar goto könnte verwendet werden, wenn die Situation es erfordert. Es gibt schlechte und böse Wege, aber wie Marshall Cline es ausdrückt, muss man manchmal zwischen den kleineren Übeln wählen. parashift.com/c++-faq-lite/big-picture.html#faq-6.15 Private Konstrukteure sind notwendig und nicht einmal schlecht für Sie. Es bedeutet nur, dass niemand, einschließlich Ihrer Unterklassen, es verwenden sollte.
Daramarak
Gotos haben zwar ihren Platz, aber wenn Sie einen privaten Konstrukteur markieren, erhalten Sie nur Probleme auf der Straße. Ich habe meinen Beitrag bearbeitet, um genauer zu erklären, warum.
BobMcGee
Es ist nicht sinnvoll , Konstrukte oder Standardkonstrukte einiger Klassen zu kopieren. In C ++ geben Sie dies an, indem Sie einen privaten ctor deklarieren, ohne ihn zu definieren (was auch für operator = üblich ist).
Bei der Optimierung von Compilern wie Java JIT und GWT werden tatsächlich private Konstruktoren verwendet: um den Umfang der Instanziierung einzuschränken und Ihren Code besser einzuschleusen / zu bereinigen.
Ajax
1

Der Konstruktor ist für einen bestimmten Zweck privat, z. B. wenn Sie Singleton implementieren oder die Anzahl der Objekte einer Klasse begrenzen müssen. Zum Beispiel müssen wir in der Singleton-Implementierung den Konstruktor privat machen

#include<iostream>
using namespace std;
class singletonClass
{


    static int i;
    static singletonClass* instance;
public:


    static singletonClass* createInstance()
    {


        if(i==0)
        {

            instance =new singletonClass;
            i=1;

        }

        return instance;

    }
    void test()
    {

        cout<<"successfully created instance";
    }
};

int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{


    singletonClass *temp=singletonClass::createInstance();//////return instance!!!
    temp->test();
}

Wenn Sie die Objekterstellung auf 10 beschränken möchten, verwenden Sie Folgendes

#include<iostream>
using namespace std;
class singletonClass
{


    static int i;
    static singletonClass* instance;
public:


    static singletonClass* createInstance()
    {


        if(i<10)
        {

            instance =new singletonClass;
            i++;
            cout<<"created";

        }

        return instance;

    }
};

int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{


    singletonClass *temp=singletonClass::createInstance();//return an instance
    singletonClass *temp1=singletonClass::createInstance();///return another instance

}

Vielen Dank

Tunvir Rahman Tusher
quelle
1

Sie können mehr als einen Konstruktor haben. C ++ bietet einen Standardkonstruktor und einen Standardkopierkonstruktor, wenn Sie keinen explizit angeben. Angenommen, Sie haben eine Klasse, die nur mit einem parametrisierten Konstruktor erstellt werden kann. Vielleicht hat es Variablen initialisiert. Wenn ein Benutzer diese Klasse dann ohne diesen Konstruktor verwendet, kann dies zu Problemen führen. Eine gute allgemeine Regel: Wenn die Standardimplementierung nicht gültig ist, machen Sie sowohl den Standardkonstruktor als auch den Kopierkonstruktor privat und geben Sie keine Implementierung an:

class C
{
public:
    C(int x);

private:
    C();
    C(const C &);
};

Verwenden Sie den Compiler, um zu verhindern, dass Benutzer das Objekt mit den ungültigen Standardkonstruktoren verwenden.

Charles
quelle
2
Wenn Sie einen nicht standardmäßigen Konstruktor angeben, ohne einen Standardkonstruktor anzugeben, ist der Standardkonstruktor nicht vorhanden. Sie müssen es nicht erstellen und privat machen.
TT_
0

Wenn Sie aus Effective Java zitieren , können Sie eine Klasse mit privatem Konstruktor haben, um eine Dienstprogrammklasse zu haben, die Konstanten definiert (als statische Endfelder).

( BEARBEITEN: Gemäß dem Kommentar ist dies möglicherweise nur mit Java anwendbar. Ich weiß nicht, ob dieses Konstrukt in anderen OO-Sprachen anwendbar ist / benötigt wird (z. B. C ++).)

Ein Beispiel wie folgt:

public class Constants {
    private Contants():

    public static final int ADDRESS_UNIT = 32;
    ...
}

EDIT_1 : Auch hier gilt die folgende Erklärung in Java: (und unter Bezugnahme auf das Buch Effective Java )

Eine Instanziierung einer Utility-Klasse wie die folgende ist zwar nicht schädlich, hat jedoch keinen Zweck, da sie nicht für die Instanziierung ausgelegt ist.

Angenommen, es gibt keinen privaten Konstruktor für Klassenkonstanten. Ein Codeblock wie unten ist gültig, vermittelt jedoch nicht besser die Absicht des Benutzers der Constants-Klasse

unit = (this.length)/new Constants().ADDRESS_UNIT;

im Gegensatz zu Code wie

unit = (this.length)/Constants.ADDRESS_UNIT;

Ich denke auch, dass ein privater Konstrukteur die Absicht des Designers der Constants (sagen wir) Klasse besser vermittelt.

Java bietet einen standardmäßigen parameterlosen öffentlichen Konstruktor, wenn kein Konstruktor bereitgestellt wird und wenn Sie die Instanziierung verhindern möchten, wird ein privater Konstruktor benötigt.

Man kann eine statische Klasse der obersten Ebene nicht markieren und sogar eine letzte Klasse kann instanziiert werden.

Sateesh
quelle
2
In C ++ benötigen Sie dafür jedoch keine Klasse. Wenn etwas nicht von Daten im Objekt abhängt, schreiben Sie es als freie Funktionen und freie Variablen. Willst du Kapselung? Verwenden Sie einen Namespace.
Daramarak
@ Daramarak: Danke, ich habe keine Erfahrung mit C ++. Ich habe die Antwort aktualisiert, um zu
berücksichtigen
2
Wenn Ihr Objekt nur statische Variablen kapselt, warum sollten Sie die Instanziierung einschränken? Warum etwas über den Konstruktor angeben? Es wird keinen Schaden anrichten, wenn es instanziiert wird. Es scheint, als könnten Sie ähnliche Ergebnisse erzielen, wenn Sie die Klasse als statisch und endgültig deklarieren.
BobMcGee
@ BobMcGee, danke für deinen Kommentar. Dies brachte mich dazu, mehr über das nachzudenken (und zu verweisen), was ich gepostet habe. Ich habe meine Antwort bearbeitet, um weitere Überlegungen zur Nützlichkeit des privaten Konstruktors hinzuzufügen.
Sateesh
0

Utility-Klassen können private Konstruktoren haben. Benutzer der Klassen sollten diese Klassen nicht instanziieren können:

public final class UtilityClass {
    private UtilityClass() {}

    public static utilityMethod1() {
        ...
    }
}
gpampara
quelle
1
Warum ist es wichtig, wenn die Utility-Klasse instanziiert wird? Alles, was es tut, ist ein Objekt ohne Felder zu erstellen und ein paar Bytes Speicher zu verbrauchen.
BobMcGee
Wenn Sie es instanziieren können, wird eine mehrdeutige API erstellt. Wenn Sie eine Klasse als Utility-Klasse ohne Status entwerfen und dies auch beibehalten möchten. Sie können eine Klasse mit einem öffentlichen Konstruktor unterordnen. Eine Unterklasse einiger Utility-Methoden ist idiotisch.
Gpampara
@ BobMcGee: Offensichtlich ist das Entwerfen einer funktionierenden Klasse und das Entwerfen einer Klasse, die von anderen Personen verwendet werden soll, etwas anderes. Diejenigen, die in der API-Entwicklung arbeiten (wie Sun People oder Google Collections Guy), werden jeden töten, der versucht zu sagen, dass ein privater Konstruktor in einer Utility-Klasse nutzlos ist.
Nanda
@gpampara: Wenn Sie Ihr Klassenfinale deklarieren, wird verhindert, dass Personen Unterklassen bilden. Dies hat Sun für die String-Klasse getan. @Nanda: Eine Utility - Klasse nicht benötigt einen definierten Konstruktor. Wenn Sie nicht möchten, dass es erweiterbar ist, deklarieren Sie es nicht mit "final".
BobMcGee
1
@ BobMcGee: Sie scheinen es zu lieben, das Beispiel von Sun zu sehen. Überprüfen Sie dann diese Dienstprogrammklasse Sammlungen von Sun: docjar.com/html/api/java/util/Collections.java.html . Es wird in der Tat ein privater Konstruktor verwendet.
Nanda
0

Möglicherweise möchten Sie verhindern, dass eine Klasse frei instanziiert wird. Sehen Sie sich das Singleton-Entwurfsmuster als Beispiel an. Um die Einzigartigkeit zu gewährleisten, darf niemand eine Instanz davon erstellen :-)

Seb
quelle
0

Eine der wichtigsten Anwendungen ist die SingleTon-Klasse

class Person
{
   private Person()
   {
      //Its private, Hense cannot be Instantiated
   }

   public static Person GetInstance()
   {
       //return new instance of Person
       // In here I will be able to access private constructor
   }
};

Es ist auch geeignet, wenn Ihre Klasse nur statische Methoden hat. dh niemand muss Ihre Klasse instanziieren

SysAdmin
quelle
Es sollte beachtet werden, dass Singleton von vielen als "Anti-Muster" angesehen wird und eine Entscheidung, es anzuwenden, nicht leichtfertig getroffen werden sollte. Eine übliche Alternative ist die Abhängigkeitsinjektion.
Michael Aaron Safyan
SingleTon ist kein Anti-Pattern. Eine übermäßige Verwendung des Musters (aufgrund mangelnder Kenntnis seiner Verwendung) ist jedoch nicht gut. Es sollte beachtet werden, dass es sich um ein GOF-Muster handelt.
SysAdmin
0

Es ist wirklich ein offensichtlicher Grund: Sie möchten ein Objekt erstellen, aber es ist nicht praktisch, dies (in Bezug auf die Schnittstelle) innerhalb des Konstruktors zu tun.

Das FactoryBeispiel ist ganz offensichtlich, lassen Sie mich die Named ConstructorRedewendung demonstrieren .

Angenommen, ich habe eine Klasse, Complexdie eine komplexe Zahl darstellen kann.

class Complex { public: Complex(double,double); .... };

Die Frage ist: Erwartet der Konstruktor den Real- und Imaginärteil oder erwartet er die Norm und den Winkel (Polarkoordinaten)?

Ich kann die Benutzeroberfläche ändern, um es einfacher zu machen:

class Complex
{
public:
  static Complex Regular(double, double = 0.0f);
  static Complex Polar(double, double = 0.0f);
private:
  Complex(double, double);
}; // class Complex

Dies wird als Named ConstructorRedewendung bezeichnet: Die Klasse kann nur von Grund auf neu erstellt werden, indem explizit angegeben wird, welchen Konstruktor wir verwenden möchten.

Es ist ein Sonderfall vieler Bauweisen. Die Entwurfsmuster bieten eine gute Anzahl von Möglichkeiten , um Bauobjekt: Builder, Factory, Abstract Factory, ... und ein privater Konstruktor wird sichergestellt , dass der Benutzer richtig eingeschränkt.

Matthieu M.
quelle
0

Neben den bekannteren Verwendungen…

So implementieren Sie das Methodenobjektmuster , das ich wie folgt zusammenfassen würde:

"Privater Konstruktor, öffentliche statische Methode"
"Objekt für die Implementierung, Funktion für die Schnittstelle"

Wenn Sie eine Funktion mithilfe eines Objekts implementieren möchten und das Objekt außerhalb einer einmaligen Berechnung (durch einen Methodenaufruf) nicht nützlich ist, verfügen Sie über ein Wegwerfobjekt . Sie können die Objekterstellung und den Methodenaufruf in einer statischen Methode kapseln, um dieses allgemeine Anti-Pattern zu verhindern:

z = new A(x,y).call();

… Durch einen (namengebundenen) Funktionsaufruf ersetzen:

z = A.f(x,y);

Der Anrufer muss niemals wissen oder sich darum kümmern, dass Sie ein Objekt intern verwenden, eine sauberere Benutzeroberfläche erhalten und verhindern, dass Müll vom Objekt herumhängt oder das Objekt falsch verwendet wird.

Zum Beispiel, wenn Sie eine Berechnung über Methoden zu brechen foo, barund zorkzum Beispiel auf Aktien Zustand ohne viele Werte passieren zu müssen in und aus Funktionen, man könnte es wie folgt implementieren:

class A {
  public static Z f(x, y) {
    A a = new A(x, y);
    a.foo();
    a.bar();
    return a.zork();
  }

  private A(X x, Y y) { /* ... */ };
}

Dieses Methodenobjektmuster finden Sie in Smalltalk Best Practice Patterns , Kent Beck, S. 34–37. Dort ist es der letzte Schritt eines Refactoring-Musters und endet mit:

  1. Ersetzen Sie die ursprüngliche Methode durch eine, die eine Instanz der neuen Klasse erstellt, die mit den Parametern und dem Empfänger der ursprünglichen Methode erstellt wurde, und rufen Sie "compute" auf.

Dies unterscheidet sich erheblich von den anderen Beispielen hier: Die Klasse ist instanziierbar (im Gegensatz zu einer Utility-Klasse), aber die Instanzen sind privat (im Gegensatz zu Factory-Methoden, einschließlich Singletons usw.) und können auf dem Stapel leben, da sie niemals entkommen.

Dieses Muster ist sehr nützlich bei Bottom-Up-OOP, bei dem Objekte verwendet werden, um die Implementierung auf niedriger Ebene zu vereinfachen, aber nicht unbedingt extern verfügbar gemacht werden, und steht im Gegensatz zu dem Top-Down-OOP, das häufig dargestellt wird und mit Schnittstellen auf hoher Ebene beginnt.

Nils von Barth
quelle
0

Manchmal ist es nützlich, wenn Sie steuern möchten, wie und wann (und wie viele) Instanzen eines Objekts erstellt werden.

Unter anderem in Mustern verwendet:

Singleton pattern
Builder pattern
ssedano
quelle
Wie ist ein privater Konstruktor in einem unveränderlichen Objekt nützlich? Bei der Unveränderlichkeit geht es darum, Änderungen an einem Objekt nach der Erstellung zu verhindern , während bei privaten Konstruktoren die Erstellung verhindert wird .
Nils von Barth
0

Die Verwendung privater Konstruktoren könnte auch dazu dienen, die Lesbarkeit / Wartbarkeit angesichts des domänengesteuerten Designs zu verbessern. Aus "Microsoft .NET - Erstellen von Anwendungen für Unternehmen, 2. Ausgabe":

var request = new OrderRequest(1234);

Zitat: "Hier gibt es zwei Probleme. Erstens kann man beim Betrachten des Codes kaum erraten, was los ist. Eine Instanz von OrderRequest wird erstellt, aber warum und mit welchen Daten? Was ist 1234? Dies führt zum zweiten Problem: Sie verletzen die allgegenwärtige Sprache des begrenzten Kontexts. Die Sprache sagt wahrscheinlich Folgendes aus: Ein Kunde kann eine Bestellanfrage stellen und darf eine Kauf-ID angeben. Wenn dies der Fall ist, können Sie hier eine neue OrderRequest-Instanz abrufen : "

var request = OrderRequest.CreateForCustomer(1234);

wo

private OrderRequest() { ... }

public OrderRequest CreateForCustomer (int customerId)
{
    var request = new OrderRequest();
    ...
    return request;
}

Ich befürworte dies nicht für jede einzelne Klasse, aber für das obige DDD-Szenario halte ich es für absolut sinnvoll, eine direkte Erstellung eines neuen Objekts zu verhindern.

Morten Nørgaard
quelle