Dlaczego powinniśmy uczynić konstruktora prywatnym w klasie? Ponieważ zawsze potrzebujemy, aby konstruktor był publiczny.
134
Niektóre powody, dla których możesz potrzebować prywatnego konstruktora:
final
poziom klasy. Z tego powodu umieszczanie prywatnego konstruktora jest praktycznie bezużyteczne.final
. To właśnie zrobił Sun dla klasy String i rozsądny fragment API, którego nie należy rozszerzać.Dostarczając prywatnego konstruktora zapobiegasz tworzeniu instancji klas w innym miejscu niż ta sama klasa. Istnieje kilka przypadków użycia takich konstruktorów.
A. Instancje klasy są tworzone w
static
metodzie.static
Metoda jest następnie uznany jakopublic
.B. Twoja klasa to singleton . Oznacza to, że w programie nie istnieje więcej niż jedna instancja Twojej klasy.
C. (Dotyczy tylko nadchodzącego standardu C ++ 0x) Masz kilka konstruktorów. Niektóre z nich są zadeklarowane
public
, inneprivate
. Aby zmniejszyć rozmiar kodu, konstruktorzy publiczni „wywołują” konstruktory prywatne, które z kolei wykonują całą pracę. Twojepublic
konstruktory są więc nazywane konstruktorami delegującymi :D. Chcesz ograniczyć kopiowanie obiektów (na przykład z powodu korzystania z udostępnionego zasobu):
E. Twoja klasa jest klasą użytkową . Oznacza to, że zawiera tylko
static
członków. W takim przypadku w programie nie wolno nigdy tworzyć instancji obiektu.źródło
Pozostawić „tylne drzwi”, które pozwalają innej klasie / funkcji znajomego na skonstruowanie obiektu w sposób zabroniony użytkownikowi. Przykładem, który przychodzi na myśl, byłby kontener konstruujący iterator (C ++):
źródło
friend
tego, gdy nie jest to uzasadnione - i jest wiele przypadków, w których jest to zły pomysł. Niestety, wiadomość została zbyt dobrze przyjęta i wielu programistów nigdy nie uczy się języka na tyle dobrze, aby zrozumieć, że sporadyczne używaniefriend
jest nie tylko dopuszczalne, ale i preferowane . Twój przykład był właśnie takim przypadkiem. Celowe silne połączenie nie jest przestępstwem, to decyzja projektowa.Każdy utknął w sprawie Singletona, wow.
Inne rzeczy:
źródło
Może to być bardzo przydatne w przypadku konstruktora, który zawiera wspólny kod; konstruktory prywatne mogą być wywoływane przez inne konstruktory przy użyciu opcji „this (...);” notacja. Tworząc wspólny kod inicjujący w konstruktorze prywatnym (lub chronionym), wyraźnie dajesz również do zrozumienia, że jest on wywoływany tylko podczas konstrukcji, co nie jest tak, gdyby była po prostu metodą:
źródło
W niektórych przypadkach możesz nie chcieć używać konstruktora publicznego; na przykład, jeśli chcesz klasę singleton.
Jeśli piszesz zestaw używany przez strony trzecie, może istnieć kilka klas wewnętrznych, które chcesz utworzyć tylko przez swój zestaw, a nie mają być tworzone przez użytkowników zestawu.
źródło
Gwarantuje to, że Ty (klasa z prywatnym konstruktorem) kontrolujesz sposób wywoływania konstruktora.
Przykład: statyczna metoda fabryczna klasy może zwracać obiekty, gdy metoda fabryki zdecyduje się je przydzielić (na przykład pojedyncza fabryka).
źródło
Możemy też mieć prywatnego konstruktora, który umożliwi stworzenie obiektu tylko przez określoną klasę (ze względów bezpieczeństwa).
Jednym ze sposobów jest zorganizowanie zajęć z przyjaciółmi.
Przykład w C ++:
Uwaga: Uwaga: tylko ClientClass (ponieważ jest przyjacielem SecureClass) może wywoływać Konstruktora SecureClass.
źródło
Oto niektóre zastosowania prywatnego konstruktora:
źródło
jeśli nie chcesz, aby użytkownicy tworzyli instancje tej klasy lub tworzyli klasę, która dziedziczy tę klasę, jak np.
java.lang.math
, cała funkcja w tym pakiecie jeststatic
, wszystkie funkcje można wywołać bez tworzenia instancjimath
, więc konstruktor jest ogłaszany jako statyczny .źródło
Jeśli jest prywatny, nie możesz go nazwać ==> nie możesz utworzyć instancji klasy. Przydatne w niektórych przypadkach, na przykład singleton.
Jest dyskusja i kilka przykładów tutaj .
źródło
Widziałem Twoje pytanie dotyczące tego samego problemu.
Po prostu, jeśli nie chcesz pozwalać innym na tworzenie instancji, trzymaj konstruktor w ograniczonym zakresie. Praktyczne zastosowanie (przykład) to wzorzec singleton.
źródło
Nie powinieneś ustawiać konstruktora jako prywatnego. Kropka. Zadbaj o ochronę, aby w razie potrzeby przedłużyć klasę.
Edycja: Stoję przy tym, bez względu na to, ile głosów przeciw temu rzucisz. Odcinasz potencjał przyszłego rozwoju kodu. Jeśli inni użytkownicy lub programiści są naprawdę zdeterminowani, aby rozszerzyć klasę, po prostu zmienią konstruktor na chroniony w kodzie źródłowym lub bajtowym. Nie osiągniesz nic poza tym, że ich życie będzie trochę trudniejsze. Dołącz ostrzeżenie w komentarzach konstruktora i tak to zostaw.
Jeśli jest to klasa użytkowa, prostszym, poprawniejszym i bardziej eleganckim rozwiązaniem jest oznaczenie całej klasy „statycznym końcem”, aby zapobiec rozszerzaniu. Samo oznaczenie konstruktora jako prywatnego nie przyniesie nic dobrego; naprawdę zdeterminowany użytkownik może zawsze użyć refleksji, aby uzyskać konstruktora.
Prawidłowe zastosowania:
protected
konstruktora jest wymuszenie użycia statycznych metod fabryki, które pozwalają na ograniczenie tworzenia instancji lub puli i ponownego wykorzystania kosztownych zasobów (połączenia z bazą danych, zasoby natywne).źródło
Konstruktor jest prywatny w niektórych celach, na przykład gdy trzeba zaimplementować singleton lub ograniczyć liczbę obiektów klasy. Na przykład w implementacji singletona musimy ustawić konstruktor jako prywatny
Ponownie, jeśli chcesz ograniczyć tworzenie obiektu do 10, użyj następującego
Dzięki
źródło
Możesz mieć więcej niż jednego konstruktora. C ++ udostępnia domyślny konstruktor i domyślny konstruktor kopiujący, jeśli nie podasz go jawnie. Załóżmy, że masz klasę, którą można zbudować tylko przy użyciu sparametryzowanego konstruktora. Może zainicjował zmienne. Jeśli użytkownik użyje tej klasy bez tego konstruktora, może to spowodować niekończące się problemy. Dobra zasada ogólna: jeśli domyślna implementacja jest nieprawidłowa, ustaw konstruktor domyślny i kopiujący jako prywatne i nie podawaj implementacji:
Użyj kompilatora, aby uniemożliwić użytkownikom używanie obiektu z domyślnymi konstruktorami, które są nieprawidłowe.
źródło
Cytat z Effective Java , możesz mieć klasę z prywatnym konstruktorem, aby mieć klasę narzędziową, która definiuje stałe (jako statyczne pola końcowe).
( EDYTUJ: zgodnie z komentarzem jest to coś, co może mieć zastosowanie tylko w Javie, nie wiem, czy ta konstrukcja ma zastosowanie / jest potrzebna w innych językach OO (powiedzmy C ++))
Przykład jak poniżej:
EDIT_1 : Ponownie, poniższe wyjaśnienie ma zastosowanie w Javie: (i na podstawie książki Effective Java )
Instancja klasy użytkowej takiej jak ta poniżej, choć nie jest szkodliwa, nie służy żadnemu celowi, ponieważ nie została zaprojektowana do tworzenia instancji.
Na przykład załóżmy, że nie ma prywatnego konstruktora dla stałych klasy. Fragment kodu jak poniżej jest prawidłowy, ale nie lepiej oddaje intencji użytkownika klasy Constants
w przeciwieństwie do kodu takiego jak
Myślę też, że prywatny konstruktor lepiej oddaje intencje projektanta klasy Constants (powiedzmy).
Java udostępnia domyślny konstruktor publiczny bez parametrów, jeśli nie jest dostarczony żaden konstruktor, a jeśli zamierzasz zapobiec tworzeniu instancji, potrzebny jest konstruktor prywatny.
Nie można oznaczyć jako statycznej klasy najwyższego poziomu, a nawet można utworzyć instancję klasy końcowej.
źródło
Klasy narzędziowe mogą mieć prywatnych konstruktorów. Użytkownicy klas nie powinni mieć możliwości tworzenia instancji tych klas:
źródło
Możesz chcieć uniemożliwić swobodne tworzenie instancji klasy. Zobacz wzorzec projektowania singleton jako przykład. Aby zagwarantować wyjątkowość, nie możesz pozwolić nikomu stworzyć jej instancji :-)
źródło
Jednym z ważnych zastosowań jest klasa SingleTon
Jest również odpowiedni, jeśli twoja klasa ma tylko metody statyczne. tj. nikt nie musi tworzyć instancji Twojej klasy
źródło
To naprawdę jeden oczywisty powód: chcesz zbudować obiekt, ale nie jest to praktyczne (jeśli chodzi o interfejs) w konstruktorze.
Factory
Przykładem jest dość oczywiste, pozwól mi zademonstrowaćNamed Constructor
idiom.Powiedzmy, że mam klasę,
Complex
która może reprezentować liczbę zespoloną.Pytanie brzmi: czy konstruktor oczekuje części rzeczywistej i urojonej, czy też oczekuje normy i kąta (współrzędne biegunowe)?
Mogę zmienić interfejs, żeby było łatwiej:
Nazywa się to
Named Constructor
idiomem: klasę można zbudować tylko od zera, jawnie podając, którego konstruktora chcemy użyć.To szczególny przypadek wielu metod konstrukcyjnych. Wzorce projektowe zapewniają dużą liczbę sposobów budowania obiektu:
Builder
,Factory
,Abstract Factory
, ... i prywatny konstruktor będzie upewnić się, że użytkownik jest odpowiednio ograniczany.źródło
Oprócz bardziej znanych zastosowań…
Aby zaimplementować wzorzec Method Object , który podsumowałbym jako:
Jeśli chcesz zaimplementować funkcję za pomocą obiektu, a obiekt nie jest przydatny poza wykonaniem jednorazowych obliczeń (przez wywołanie metody), masz obiekt Throwaway . Możesz hermetyzować tworzenie obiektu i wywołanie metody w metodzie statycznej, zapobiegając temu typowemu anty-wzorcowi:
… Zastępując go wywołaniem funkcji (z przestrzenią nazw):
Wzywający nigdy nie musi wiedzieć ani dbać o to, że używasz obiektu wewnętrznie, uzyskując bardziej przejrzysty interfejs i zapobiegając śmieciom z obiektu wiszącego w pobliżu lub nieprawidłowego użycia obiektu.
Na przykład, jeśli chcesz, aby rozbić obliczenia całej metody
foo
,bar
izork
, na przykład do stanu zakładowego bez konieczności przechodzenia wiele wartości i wyjść z funkcji, można go realizować w następujący sposób:Ten wzorzec Method Object jest podany w Smalltalk Best Practice Patterns , Kent Beck, strony 34–37, gdzie jest ostatnim krokiem wzorca refaktoryzacji, kończącym się:
Różni się to znacznie od innych przykładów tutaj: klasa jest instancyjna (w przeciwieństwie do klasy użytkowej), ale instancje są prywatne (w przeciwieństwie do metod fabrycznych, w tym singletonów itp.) I mogą żyć na stosie, ponieważ nigdy nie uciekają.
Ten wzorzec jest bardzo przydatny w OOP od dołu do góry, gdzie obiekty są używane do uproszczenia implementacji niskiego poziomu, ale niekoniecznie są ujawniane zewnętrznie i kontrastuje z odgórnym OOP, które jest często prezentowane i zaczyna się od interfejsów wysokiego poziomu.
źródło
Czasami jest to przydatne, jeśli chcesz kontrolować, jak i kiedy (i ile) instancji obiektu jest tworzonych.
Między innymi stosowane we wzorach:
źródło
Korzystanie z prywatnych konstruktorów może również zwiększyć czytelność / łatwość konserwacji w obliczu projektowania opartego na domenie. Z „Microsoft .NET - Aplikacje do projektowania architektury dla przedsiębiorstw, wydanie 2”:
Cytuj: „Występują tu dwa problemy. Po pierwsze, patrząc na kod, trudno zgadnąć, co się dzieje. Tworzona jest instancja OrderRequest, ale dlaczego i przy użyciu jakich danych? Co to jest 1234? Prowadzi to do drugiego problemu: naruszasz wszechobecny język ograniczonego kontekstu. Język prawdopodobnie mówi mniej więcej tak: klient może złożyć żądanie zamówienia i może podać identyfikator zakupu. W takim przypadku jest lepszy sposób na uzyskanie nowej instancji OrderRequest : "
gdzie
Nie zalecam tego dla każdej klasy, ale dla powyższego scenariusza DDD myślę, że ma sens zapobieganie bezpośredniemu tworzeniu nowego obiektu.
źródło