Apakah ada alternatif yang layak untuk GOF Singleton Pattern?


91

Mari kita hadapi itu. Pola Singleton adalah topik yang sangat kontroversial dengan pemrogram gerombolan di kedua sisi pagar. Ada orang yang merasa bahwa Singleton tidak lebih dari variabel global yang dimuliakan, dan ada pula yang bersumpah demi pola dan menggunakannya tanpa henti. Saya tidak ingin Kontroversi Singleton berada di inti pertanyaan saya. Setiap orang dapat melakukan tarik tambang dan bertempur habis-habisan dan melihat siapa yang menang untuk semua yang saya pedulikan . Yang ingin saya katakan adalah, saya tidak percaya ada satu jawaban yang benar dan saya tidak sengaja mencoba mengobarkan pertengkaran partisan. Saya hanya tertarik pada alternatif tunggal ketika saya mengajukan pertanyaan:

Apakah ada alternatif khusus mereka untuk GOF Singleton Pattern?

Misalnya, berkali-kali ketika saya telah menggunakan pola tunggal di masa lalu, saya hanya tertarik untuk mempertahankan status / nilai dari satu atau beberapa variabel. Status / nilai variabel, bagaimanapun, dapat dipertahankan antara setiap instansiasi kelas menggunakan variabel statis daripada menggunakan pola tunggal.

Ide lain apa yang Anda miliki?

EDIT: Saya tidak ingin ini menjadi posting lain tentang "cara menggunakan singleton dengan benar." Sekali lagi, saya mencari cara untuk menghindarinya. Untuk bersenang-senang, oke? Saya kira saya mengajukan pertanyaan akademis murni dengan suara trailer film terbaik Anda, "Di alam semesta paralel di mana tidak ada singleton, apa yang bisa kita lakukan?"


Apa? Ini tidak baik atau buruk, tapi bagaimana saya bisa menggantinya? Untuk semua orang yang mengatakan itu bagus - jangan berpartisipasi. Semua orang yang mengatakan itu buruk, buktikan dengan menunjukkan kepada saya bagaimana saya bisa hidup tanpanya. Kedengarannya Argumentatif bagi saya.
S. Lott

@CodingWithoutComents: membaca seluruh kiriman. Begitulah cara saya mendapat kesan "jangan membalas jika Anda menganggap Singletons baik-baik saja".
S. Lotot

2
Nah, jika itu yang terjadi, saya minta maaf. Saya pikir saya mengambil langkah signifikan untuk menghindari polarisasi. Saya pikir saya mengajukan pertanyaan sedemikian rupa sehingga baik pecinta dan pembenci Singletons sama-sama bisa
mengerti

Jika saya menggunakan Singletons, saya tidak memiliki kemungkinan kontribusi tentang cara mengatasi mereka. Kedengarannya terpolarisasi bagi saya.
S. Lotot

9
Saya menggunakan Singletons setiap hari, tetapi apakah itu menghentikan saya untuk berpikir bahwa mungkin ada cara yang lebih baik untuk melakukan sesuatu? Pola Desain baru ada selama 14 tahun. Apakah saya menganggapnya sebagai kebenaran alkitabiah? Apakah kita berhenti berpikir di luar kotak? Apakah kita tidak mencoba memajukan disiplin Ilmu Komputer?
CodingWithoutComments

Jawaban:


77

Alex Miller dalam " Patterns I Hate " mengutip yang berikut:

"Ketika seorang lajang sepertinya jawabannya, saya merasa lebih bijaksana untuk:

  1. Buat antarmuka dan implementasi default singleton Anda
  2. Buat satu contoh implementasi default Anda di "atas" sistem Anda. Ini mungkin dalam konfigurasi Spring, atau dalam kode, atau didefinisikan dalam berbagai cara tergantung pada sistem Anda.
  3. Meneruskan satu instance ke setiap komponen yang membutuhkannya (injeksi ketergantungan)

2
Saya tahu ini hampir berusia 5 tahun, tetapi bisakah Anda mengembangkannya? Saya rasa saya diajari bahwa cara yang benar untuk membuat singleton adalah dengan sebuah antarmuka. Saya akan tertarik jika apa yang saya lakukan adalah 'OK', dan tidak seburuk yang saya diberitahu.
Pureferret

97

Untuk memahami cara yang tepat untuk mengatasi Singletons, Anda perlu memahami apa yang salah dengan Singletons (dan status global secara umum):

Lajang menyembunyikan dependensi.

Mengapa itu penting?

Karena Jika Anda menyembunyikan dependensi, Anda cenderung kehilangan jejak jumlah kopling.

Anda mungkin membantahnya

void purchaseLaptop(String creditCardNumber, int price){
  CreditCardProcessor.getInstance().debit(creditCardNumber, amount);
  Cart.getInstance().addLaptop();
}

lebih sederhana dari

void purchaseLaptop(CreditCardProcessor creditCardProcessor, Cart cart, 
                    String creditCardNumber, int price){
  creditCardProcessor.debit(creditCardNumber, amount);
  cart.addLaptop();
}

tapi setidaknya API kedua memperjelas apa sebenarnya kolaborator metode tersebut.

Jadi cara untuk mengatasi Singletons bukanlah dengan menggunakan variabel statis atau pelacak layanan, tetapi untuk mengubah kelas Singleton menjadi instance, yang dibuat dalam lingkup di mana mereka masuk akal dan dimasukkan ke dalam komponen dan metode yang membutuhkannya. Anda mungkin menggunakan kerangka kerja IoC untuk menangani ini, atau Anda mungkin melakukannya secara manual, tetapi yang penting adalah menyingkirkan status global Anda dan membuat dependensi dan kolaborasi menjadi eksplisit.


+1 Untuk membahas akar masalahnya, bukan hanya bagaimana menyiasatinya.
Phil

9
Dalam aplikasi multi-tingkat yang lengkap, metode kedua sering kali membuat sejumlah besar kode yang tidak perlu. Dengan mencemari kode tingkat menengah dengan logika untuk dibawa ke tingkat yang lebih rendah, objek yang sebenarnya tidak diperlukan pada tingkat itu, bukankah kita membuat dependensi yang tidak perlu? Katakanlah tingkat 4 dalam tumpukan navigasi memulai tindakan latar belakang, seperti mengunggah file. Sekarang katakanlah Anda ingin memperingatkan pengguna ketika selesai tetapi pada saat itu, pengguna mungkin berada di bagian aplikasi yang sama sekali berbeda yang hanya berbagi tingkat 1 yang sama dengan tampilan awal. Ton kode yang tidak dibutuhkan ...
Hari Karam Singh

1
@RasmusFaber Pola Singleton tidak menyembunyikan dependensi. Keluhan Anda tentang menyembunyikan dependensi adalah masalah terpisah dari polanya. Memang benar bahwa pola memudahkan untuk membuat kesalahan ini, tetapi sangat mungkin untuk mengeksekusi pola IoC dan Singleton bersama-sama secara harmonis. Misalnya, saya dapat membuat lib pihak ketiga yang memerlukan manajemen siklus hidup khusus untuk instance-nya, dan siapa pun yang menggunakan lib saya harus tetap "meneruskan" instance singleton saya ke kelas mereka menggunakan Dependency Injection klasik daripada "sky hook" singleton saya dari setiap pointcut.
Martin Bliss

@HariKaramSingh Anda dapat menggunakan pola subscribe / publish atau event bus di seluruh sistem (yang harus dibagikan ke semua pihak terkait, bukan tunggal) untuk mengatasi masalah ini.
Victor Sorokin

4
Juga pola pub / sub atau pengamat bisa sama buruknya dengan "kehilangan jejak penggandengan" seperti yang akan dibuktikan oleh siapa pun yang harus melangkah men-debug melalui kerangka kerja yang sangat bergantung padanya. Setidaknya dengan singleton, nama metode yang dipanggil berada di tempat yang sama dengan kode pemanggilan :) Secara pribadi, saya pikir semua strategi ini memiliki tempatnya dan tidak ada yang dapat diterapkan secara membabi buta. Pembuat kode ceroboh akan membuat spageti dari pola apa pun dan pembuat kode yang bertanggung jawab tidak perlu membebani diri mereka secara berlebihan dengan batasan ideologis untuk membuat kode yang elegan.
Hari Karam Singh

14

Solusi terbaik yang saya temukan adalah menggunakan pola pabrik untuk membuat instance kelas Anda. Dengan menggunakan pola tersebut, Anda dapat memastikan bahwa hanya ada satu instance kelas yang dibagikan di antara objek yang menggunakannya.

Saya pikir ini akan rumit untuk mengelolanya, tetapi setelah membaca posting blog ini "Kemana Semua Jomblo Pergi?" , sepertinya sangat alami. Dan sebagai tambahan, ini sangat membantu dengan mengisolasi pengujian unit Anda.

Singkatnya, apa yang perlu Anda lakukan? Setiap kali sebuah objek bergantung pada yang lain, itu akan menerima turunannya hanya melalui konstruktornya (tidak ada kata kunci baru di kelas Anda).

class NeedyClass {

    private ExSingletonClass exSingleton;

    public NeedyClass(ExSingletonClass exSingleton){
        this.exSingleton = exSingleton;
    }

    // Here goes some code that uses the exSingleton object
}

Dan kemudian, pabrik.

class FactoryOfNeedy {

    private ExSingletonClass exSingleton;

    public FactoryOfNeedy() {
        this.exSingleton = new ExSingletonClass();
    }

    public NeedyClass buildNeedy() {
        return new NeedyClass(this.exSingleton);
    }
}

Karena Anda hanya akan membuat instance pabrik satu kali, akan ada satu instance exSingleton. Setiap kali Anda memanggil buildNeedy, instance baru NeedyClass akan dibundel dengan exSingleton.

Saya harap ini membantu. Tolong tunjukkan jika ada kesalahan.


5
untuk memastikan Pabrik Anda dibuat instance-nya hanya setelah Anda memerlukan konstruktor pribadi dan menetapkan metode buildNeedy sebagai metode statis.
Julien Grenier

16
Julien benar, perbaikan ini memiliki kelemahan mendasar, yaitu Anda secara implisit mengatakan Anda hanya dapat membuat contoh satu pabrik. Jika Anda mengambil tindakan pencegahan yang diperlukan untuk memastikan bahwa hanya satu pabrik yang dibuat (seperti yang dikatakan Julien), Anda akan berakhir dengan ... satu perusahaan! Pada kenyataannya pendekatan ini hanya menambahkan lapisan abstraksi yang tidak perlu di atas singleton.
Bob Somers

Ada cara lain untuk memiliki hanya satu Mesin Virtual. Anda dapat membuat instantiate pabrik Anda hanya sekali. Tidak perlu memaksakan ini oleh kompilator. Ini juga membantu dengan unittests di mana Anda menginginkan contoh yang berbeda.
frast

Ini adalah solusi terbaik yang pernah saya lihat untuk masalah yang salah diselesaikan dengan lajang - menambahkan dependensi tanpa mengacaukan setiap panggilan metode (dan karena itu mendesain ulang antarmuka dan refactoring dependensinya). Sedikit modifikasi sangat cocok untuk situasi saya di mana tidaklah penting bahwa hanya ada satu contoh dari "tunggal", tetapi penting bahwa setiap orang akan berbagi contoh yang sama secara default (modifikasinya adalah: daripada menggunakan pabrik, gunakan statis metode untuk menyetel contoh umum secara eksternal, dan menggunakan contoh itu selama konstruksi).
meustrus

Jadi pada dasarnya keuntungan dari pendekatan ini adalah bahwa Anda hanya perlu mengocok sekitar satu contoh objek (pabrik) daripada kemungkinan sejumlah besar objek (yang Anda pilih untuk tidak menggunakan Singletons)?
Hari Karam Singh

9

Spring atau IoC-Container lainnya melakukan pekerjaan yang cukup baik dalam hal itu. Karena kelas dibuat dan dikelola di luar aplikasi itu sendiri, penampung dapat membuat kelas sederhana menjadi tunggal dan memasukkannya jika diperlukan.


Punya tautan tentang topik yang disebutkan di atas?
CodingWithoutComments

Kerangka kerja ini tampaknya khusus untuk java - ada opsi khusus bahasa lainnya? Atau bahasa-agnostik?
CodingWithoutComments

untuk .NET: Castle Windsor castleproject.org/container/index.html Microsoft Unity msdn.microsoft.com/en-us/library/cc468366.aspx Unity sebenarnya adalah kerangka kerja injeksi ketergantungan, tetapi mungkin akan berfungsi untuk topik ini.
Erik van Brakel

1
mengapa tidak terlalu banyak suara untuk ini? IOC adalah solusi sempurna untuk menghindari Singleton.
Sandeep Jindal

@CodingWoutComments Saya tahu PHP memiliki Symfony Service Container. Para pria ruby ​​memiliki cara lain untuk menyuntikkan ketergantungan. Apakah Anda memiliki bahasa tertentu yang Anda minati?
Bevelopper

9

Anda tidak harus keluar dari cara Anda untuk menghindari pola apa pun. Penggunaan pola adalah keputusan desain atau kesesuaian alami (hal itu terjadi begitu saja). Saat Anda mendesain sistem, Anda memiliki pilihan untuk menggunakan pola atau tidak menggunakan pola. Namun, Anda tidak boleh berusaha keras untuk menghindari apa pun yang pada akhirnya menjadi pilihan desain.

Saya tidak menghindari Pola Singleton. Entah itu sesuai dan saya menggunakannya atau tidak sesuai dan saya tidak menggunakannya. Saya yakin sesederhana itu.

Kesesuaian (atau ketiadaan) Singleton bergantung pada situasinya. Ini adalah keputusan desain yang harus dibuat dan konsekuensi dari keputusan itu harus dipahami (dan didokumentasikan).


Saya akan mengatakan hal yang sama, tetapi itu tidak menjawab pertanyaannya :)
Swati

2
Tolong bicarakan dalam jawaban Anda kapan itu sesuai atau tidak sesuai. Cukup Tolong.
CodingWithoutComments

Itu menjawab pertanyaan itu. Saya tidak memiliki teknik untuk menghindari penggunaan Pola Singleton karena saya tidak berusaha keras untuk menghindarinya, dan menurut saya tidak ada pengembang yang harus melakukannya.
Thomas Owens

Saya tidak berpikir Anda bisa menggeneralisasi kapan itu tepat atau tidak tepat. Itu semua spesifik proyek, dan sangat bergantung pada desain sistem yang bersangkutan. Saya tidak menggunakan "aturan praktis" untuk keputusan seperti ini.
Thomas Owens

Hmm. Saya tidak mengerti mengapa ini ditolak. Saya menjawab pertanyaan - Apa teknik Anda untuk menghindari penggunaan Pola Singleton? - dengan mengatakan bahwa saya tidak memiliki teknik karena saya tidak berusaha keras untuk menghindari pola tersebut. Bisakah para downvoters menguraikan alasan mereka?
Thomas Owens

5

Monostate (dijelaskan dalam Pengembangan Perangkat Lunak Agile Robert C. Martin) adalah alternatif untuk tunggal. Dalam pola ini, data kelas semuanya statis tetapi getter / setter tidak statis.

Sebagai contoh:

public class MonoStateExample
{
    private static int x;

    public int getX()
    {
        return x;
    }

    public void setX(int xVal)
    {
        x = xVal;
    }
}

public class MonoDriver
{
    public static void main(String args[])
    {
        MonoStateExample m1 = new MonoStateExample();
        m1.setX(10);

        MonoStateExample m2 = new MonoStateExample();
        if(m1.getX() == m2.getX())
        {
            //singleton behavior
        }
    }
}

Monostate memiliki perilaku yang mirip dengan singleton tetapi melakukannya dengan cara di mana programmer tidak selalu menyadari fakta bahwa singleton sedang digunakan.


Ini membutuhkan lebih banyak suara; Saya datang ke sini dari Google mencari penyegar MonoState!
mahemoff

@Mark Menurut saya desain ini sangat sulit dikunci dalam hal keamanan utas. Apakah saya membuat kunci instance untuk setiap variabel statis di MonoStateExample, atau apakah saya membuat satu kunci yang dimanfaatkan semua properti? Keduanya memiliki konsekuensi serius yang dapat dengan mudah diselesaikan dijalankan dalam pola Singleton.
Martin Bliss

Contoh ini adalah alternatif dari pola Singleton, tetapi tidak memecahkan masalah pola Singleton.
Sandeep Jindal

4

The tunggal Pola ada karena ada situasi ketika sebuah objek tunggal diperlukan untuk memberikan satu set layanan .

Bahkan jika ini kasusnya, saya masih mempertimbangkan pendekatan membuat lajang dengan menggunakan bidang / properti statis global yang mewakili instance, tidak sesuai. Itu tidak pantas karena itu membuat ketergantungan dalam kode antara bidang statis dan objek bukan, layanan yang disediakan objek.

Jadi, alih-alih pola klasik tunggal, saya sarankan untuk menggunakan pola layanan 'suka' dengan wadah yang dilayani , di mana alih-alih menggunakan tunggal Anda melalui bidang statis, Anda mendapatkan referensi ke sana melalui metode yang meminta jenis layanan yang diperlukan.

*pseudocode* currentContainer.GetServiceByObjectType(singletonType)
//Under the covers the object might be a singleton, but this is hidden to the consumer.

bukannya global tunggal

*pseudocode* singletonType.Instance

Dengan cara ini ketika Anda ingin mengubah jenis objek dari tunggal ke yang lain, Anda akan memiliki waktu dan waktu yang mudah untuk melakukannya. Juga sebagai manfaat tambahan Anda tidak perlu membagikan semua instance objek ke setiap metode.

Juga lihat Pembalikan Kontrol , idenya adalah dengan mengekspos lajang secara langsung ke konsumen, Anda membuat ketergantungan antara konsumen dan contoh objek, bukan layanan objek yang disediakan oleh objek.

Pendapat saya adalah menyembunyikan penggunaan pola tunggal bila memungkinkan, karena tidak selalu mungkin untuk menghindarinya, atau diinginkan.


Saya tidak begitu mengikuti contoh wadah servis Anda. Apakah Anda memiliki sumber daya online yang dapat Anda tautkan?
CodingWithoutComments

Lihat "Castle Project - Windsor Container" castleproject.org/container/index.html . Sayangnya, sangat sulit untuk menemukan publikasi abstrak tentang topik ini.
Pop Catalin

2

Jika Anda menggunakan Singleton untuk mewakili satu objek data, sebagai gantinya Anda bisa meneruskan objek data sebagai parameter metode.

(meskipun, saya berpendapat ini adalah cara yang salah untuk menggunakan Singleton sejak awal)


1

Jika masalah Anda adalah ingin mempertahankan status, Anda menginginkan kelas MumbleManager. Sebelum Anda mulai bekerja dengan sistem, klien Anda membuat MumbleManager, di mana Mumble adalah nama sistemnya. Negara dipertahankan melalui itu. Kemungkinan MumbleManager Anda akan berisi tas properti yang menahan status Anda.

Jenis gaya ini terasa sangat mirip C dan bukan seperti objek - Anda akan menemukan bahwa objek yang menentukan sistem Anda semuanya akan memiliki referensi ke MumbleManager yang sama.


Tanpa mendukung atau menentang Singleton, saya harus mengatakan bahwa solusi ini adalah anti-pola. MumbleManager menjadi "kelas Dewa" yang berisi semua jenis pengetahuan yang berbeda, melanggar Tanggung Jawab Tunggal. Ini mungkin juga menjadi Singleton untuk semua perawatan aplikasi.
Martin Bliss

0

Gunakan benda biasa dan benda pabrik. Pabrik bertanggung jawab untuk mengawasi instance dan detail objek biasa hanya dengan informasi konfigurasi (misalnya di dalamnya) dan perilaku.


1
Bukankah Pabrik sering kali tunggal? Begitulah cara saya biasanya melihat pola Pabrik diimplementasikan.
Thomas Owens

0

Sebenarnya jika Anda mendesain langsung dari awal untuk menghindari Singeltons, Anda mungkin tidak perlu bekerja keras untuk tidak menggunakan Singletons dengan menggunakan variabel statis. Saat menggunakan variabel statis, Anda juga membuat Singleton lebih atau kurang, satu-satunya perbedaan adalah Anda membuat contoh objek yang berbeda, namun secara internal mereka semua berperilaku seolah-olah mereka menggunakan Singleton.

Dapatkah Anda memberikan contoh detail di mana Anda menggunakan Singleton atau di mana Singleton saat ini digunakan dan Anda mencoba untuk menghindari penggunaannya? Ini dapat membantu orang untuk menemukan solusi yang lebih mewah bagaimana situasi dapat ditangani tanpa Singleton sama sekali.

BTW, saya pribadi tidak punya masalah dengan Singletons dan saya tidak bisa memahami masalah orang lain tentang Singletons. Saya tidak melihat hal buruk tentang mereka. Artinya, jika Anda tidak menyalahgunakannya. Setiap teknik yang berguna dapat disalahgunakan dan jika disalahgunakan, itu akan menyebabkan hasil yang negatif. Teknik lain yang sering disalahgunakan adalah warisan. Tetap saja tidak ada yang akan mengatakan warisan adalah sesuatu yang buruk hanya karena beberapa orang menyalahgunakannya dengan kejam.


0

Secara pribadi bagi saya cara yang jauh lebih masuk akal untuk mengimplementasikan sesuatu yang berperilaku seperti tunggal adalah dengan menggunakan kelas yang sepenuhnya statis (anggota statis, metode statis, properti statis). Sebagian besar waktu saya menerapkannya dengan cara ini (saya tidak dapat memikirkan perbedaan perilaku apa pun dari sudut pandang pengguna)


0

Saya pikir tempat terbaik untuk mengawasi singleton adalah di tingkat desain kelas. Pada tahap ini, Anda harus dapat memetakan interaksi antar kelas dan melihat apakah sesuatu benar-benar memerlukan bahwa hanya 1 instance dari kelas ini yang pernah ada setiap saat dalam masa pakai aplikasi.

Jika itu masalahnya, maka Anda memiliki singleton. Jika Anda memasukkan lajang sebagai kenyamanan selama pengkodean maka Anda harus benar-benar meninjau kembali desain Anda dan juga menghentikan pengkodean kata lajang :)

Dan ya, 'polisi' adalah kata yang saya maksud di sini daripada 'menghindari'. Singleton bukanlah sesuatu yang harus dihindari (dengan cara yang sama bahwa variabel goto dan global bukanlah sesuatu yang harus dihindari). Sebaliknya, Anda harus memantau penggunaannya dan memastikan bahwa itu adalah metode terbaik untuk menyelesaikan apa yang Anda inginkan secara efektif.


1
Saya sangat mengerti apa yang Anda katakan, workmad. Dan saya sangat setuju. Namun, jawaban Anda masih belum menjawab pertanyaan saya secara spesifik. Saya tidak ingin ini menjadi pertanyaan lain tentang "kapan tepat menggunakan singleton?" Saya hanya tertarik pada alternatif yang layak untuk singleton.
CodingWithoutComments

0

Saya menggunakan singleton kebanyakan sebagai "wadah metode", tanpa status sama sekali. Jika saya perlu berbagi metode ini dengan banyak kelas dan ingin menghindari beban instantiasi dan inisialisasi, saya membuat konteks / sesi dan menginisialisasi semua kelas di sana; segala sesuatu yang mengacu pada sesi juga memiliki akses ke "singleton" yang terkandung.


0

Karena tidak diprogram dalam lingkungan yang sangat berorientasi objek (misalnya Java), saya tidak sepenuhnya memahami seluk-beluk diskusi. Tetapi saya telah mengimplementasikan singleton di PHP 4. Saya melakukannya sebagai cara untuk membuat handler database 'kotak hitam' yang secara otomatis diinisialisasi dan tidak harus dilewatkan ke atas dan ke bawah pemanggilan fungsi dalam kerangka yang tidak lengkap dan agak rusak.

Setelah membaca beberapa tautan pola tunggal, saya tidak sepenuhnya yakin saya akan menerapkannya dengan cara yang sama lagi. Apa yang benar-benar dibutuhkan adalah beberapa objek dengan penyimpanan bersama (misalnya pegangan database yang sebenarnya) dan inilah yang menjadi panggilan saya.

Seperti kebanyakan pola dan algoritme, menggunakan singleton 'hanya karena keren' adalah The Wrong Thing To Do. Saya benar-benar membutuhkan panggilan 'kotak hitam' yang kebetulan terlihat sangat lajang. Dan IMO itulah cara untuk menjawab pertanyaan: perhatikan polanya, tetapi juga lihat cakupannya yang lebih luas dan pada tingkat apa instansinya perlu unik.


-1

Apa maksud Anda, apa teknik saya untuk menghindarinya?

Untuk "menghindarinya", itu menyiratkan bahwa ada banyak situasi yang saya temui di mana pola tunggal secara alami cocok, dan karena itu saya harus mengambil beberapa langkah untuk meredakan situasi ini.

Tapi tidak ada. Saya tidak harus menghindari pola tunggal. Itu sama sekali tidak muncul.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.