Ano ang singleton?
Ang singleton ay isa sa mga pinakasimpleng pattern ng disenyo na maaaring ilapat sa isang klase. Minsan sinasabi ng mga tao na "isang singleton ang klase na ito," ibig sabihin, ipinapatupad ng klase na ito ang pattern ng disenyo ng singleton. Minsan kinakailangan na magsulat ng isang klase kung saan isang bagay lamang ang maaaring malikha. Halimbawa, isang klase na responsable para sa pag-log o pagkonekta sa isang database. Ang pattern ng disenyo ng Singleton ay naglalarawan kung paano natin magagawa ang ganoong gawain. Ang singleton ay isang pattern ng disenyo na gumagawa ng dalawang bagay:-
Nagbibigay ng garantiya na ang isang klase ay magkakaroon lamang ng isang instance ng klase.
-
Nagbibigay ng pandaigdigang access point sa isang instance ng klase na ito.
-
Pribadong tagabuo. Nililimitahan ang kakayahang lumikha ng mga bagay ng klase sa labas ng klase mismo.
-
Isang pampublikong static na pamamaraan na nagbabalik ng isang instance ng klase. Ang pamamaraang ito ay tinatawag na
getInstance
. Ito ang pandaigdigang access point sa instance ng klase.
Mga opsyon sa pagpapatupad
Ang pattern ng disenyo ng singleton ay ginagamit sa iba't ibang paraan. Ang bawat pagpipilian ay mabuti at masama sa sarili nitong paraan. Dito, gaya ng dati: walang perpekto, ngunit kailangan mong magsikap para dito. Ngunit una sa lahat, tukuyin natin kung ano ang mabuti at kung ano ang masama, at kung anong mga sukatan ang nakakaimpluwensya sa pagsusuri ng pagpapatupad ng isang pattern ng disenyo. Magsimula tayo sa positibo. Narito ang mga pamantayan na nagbibigay sa pagpapatupad ng juiciness at pagiging kaakit-akit:-
Lazy initialization: kapag ang isang klase ay na-load habang ang application ay tumatakbo nang eksakto kapag ito ay kinakailangan.
-
Ang pagiging simple at transparency ng code: ang sukatan, siyempre, ay subjective, ngunit mahalaga.
-
Kaligtasan ng thread: gumagana nang tama sa isang multi-threaded na kapaligiran.
-
Mataas na pagganap sa isang multi-threaded na kapaligiran: ang mga thread ay humaharang sa isa't isa nang kaunti o hindi talaga kapag nagbabahagi ng isang mapagkukunan.
-
Non-lazy initialization: kapag ang isang klase ay na-load kapag nagsimula ang application, hindi alintana kung ito ay kinakailangan o hindi (isang kabalintunaan, sa mundo ng IT ay mas mahusay na maging tamad)
-
Pagiging kumplikado at mahinang pagiging madaling mabasa ng code. Ang sukatan ay subjective din. Ipagpalagay natin na kung dugo ang manggagaling sa mga mata, ang pagpapatupad ay so-so.
-
Kakulangan ng kaligtasan ng thread. Sa madaling salita, "thread hazard". Maling operasyon sa isang multi-threaded na kapaligiran.
-
Hindi magandang pagganap sa isang multi-threaded na kapaligiran: ang mga thread ay humaharang sa bawat isa sa lahat ng oras o madalas kapag nagbabahagi ng mapagkukunan.
Code
Ngayon ay handa na kaming isaalang-alang ang iba't ibang mga opsyon sa pagpapatupad, na naglilista ng mga kalamangan at kahinaan:Simpleng Solusyon
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Ang pinakasimpleng pagpapatupad. Mga kalamangan:
-
Ang pagiging simple at transparency ng code
-
Kaligtasan ng thread
-
Mataas na pagganap sa isang multi-threaded na kapaligiran
- Hindi tamad na pagsisimula.
Tamad na Initialization
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Mga kalamangan:
-
Tamad na pagsisimula.
-
Hindi ligtas sa thread
Naka-synchronize na Accessor
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Mga kalamangan:
-
Tamad na pagsisimula.
-
Kaligtasan ng thread
-
Mahina ang pagganap sa isang multi-threaded na kapaligiran
getInstance
ay naka-synchronize, at maaari mo lamang itong ipasok nang paisa-isa. Sa katunayan, hindi namin kailangang i-synchronize ang buong pamamaraan, ngunit ang bahagi lamang nito kung saan nagsisimula kami ng isang bagong object ng klase. Ngunit hindi natin basta-basta maaaring ibalot synchronized
ang bahaging responsable sa paglikha ng bagong bagay sa isang bloke: hindi ito magbibigay ng kaligtasan sa thread. Ito ay medyo mas kumplikado. Ang tamang paraan ng pag-synchronize ay ibinigay sa ibaba:
Dobleng Sinuri ang Pag-lock
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
Mga kalamangan:
-
Tamad na pagsisimula.
-
Kaligtasan ng thread
-
Mataas na pagganap sa isang multi-threaded na kapaligiran
-
Hindi suportado sa mga bersyon ng Java na mas mababa sa 1.5 (naayos ang pabagu-bagong keyword sa bersyon 1.5)
INSTANCE
ay dapat na alinman sa final
, o volatile
. Ang huling pagpapatupad na tatalakayin natin ngayon ay Class Holder Singleton
.
May-hawak ng Klase na si Singleton
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
Mga kalamangan:
-
Tamad na pagsisimula.
-
Kaligtasan ng thread.
-
Mataas na pagganap sa isang multi-threaded na kapaligiran.
-
Para sa tamang operasyon, kinakailangan upang matiyak na ang object ng klase
Singleton
ay sinisimulan nang walang mga error. Kung hindi, ang unang paraan ng tawaggetInstance
ay magtatapos sa isang errorExceptionInInitializerError
, at lahat ng kasunod ay mabibigoNoClassDefFoundError
.
Pagpapatupad | Tamad na pagsisimula | Kaligtasan ng thread | Bilis ng multithreading | Kailan gagamitin? |
---|---|---|---|---|
Simpleng Solusyon | - | + | Mabilis | Hindi kailanman. O kapag ang tamad na pagsisimula ay hindi mahalaga. Ngunit hindi kailanman mas mahusay. |
Tamad na Initialization | + | - | Hindi maaari | Laging kapag hindi kailangan ang multithreading |
Naka-synchronize na Accessor | + | + | Dahan-dahan | Hindi kailanman. O kapag ang bilis ng trabaho sa multithreading ay hindi mahalaga. Ngunit hindi kailanman mas mahusay |
Dobleng Sinuri ang Pag-lock | + | + | Mabilis | Sa mga bihirang kaso kapag kailangan mong pangasiwaan ang mga pagbubukod kapag gumagawa ng singleton. (kapag hindi naaangkop ang Class Holder Singleton) |
May-hawak ng Klase na si Singleton | + | + | Mabilis | Laging kapag kailangan ang multithreading at may garantiya na malilikha ang isang object ng singleton class nang walang problema. |
Mga kalamangan at kahinaan ng pattern ng Singleton
Sa pangkalahatan, ginagawa ng singleton ang eksaktong inaasahan dito:-
Nagbibigay ng garantiya na ang isang klase ay magkakaroon lamang ng isang instance ng klase.
-
Nagbibigay ng pandaigdigang access point sa isang instance ng klase na ito.
-
Ang Singleton ay lumalabag sa SRP (Single Responsibility Principle) - ang klase ng Singleton, bilang karagdagan sa mga agarang responsibilidad nito, ay kumokontrol din sa bilang ng mga kopya nito.
-
Ang dependency ng isang regular na klase o pamamaraan sa isang singleton ay hindi nakikita sa pampublikong kontrata ng klase.
-
Ang mga global variable ay masama. Ang singleton sa kalaunan ay nagiging isang mabigat na global variable.
-
Ang pagkakaroon ng singleton ay binabawasan ang testability ng application sa pangkalahatan at ang mga klase na gumagamit ng singleton sa partikular.
GO TO FULL VERSION