Pengantar Pola Desain Kreasi

1. Perkenalan

Dalam rekayasa perangkat lunak, Pola Desain menjelaskan solusi yang mapan untuk masalah yang paling sering ditemui dalam desain perangkat lunak. Ini mewakili praktik terbaik yang berkembang selama periode yang lama melalui trial and error oleh pengembang perangkat lunak berpengalaman.

Design Patterns mendapatkan popularitas setelah buku Design Patterns: Elements of Reusable Object-Oriented Software diterbitkan pada tahun 1994 oleh Erich Gamma, John Vlissides, Ralph Johnson, dan Richard Helm (juga dikenal sebagai Gang of Four atau GoF).

Dalam artikel ini, kita akan menjelajahi pola desain kreasi dan tipenya. Kami juga akan melihat beberapa contoh kode dan mendiskusikan situasi ketika pola ini sesuai dengan desain kami.

2. Pola Desain Kreasi

Pola Desain Kreasi berkaitan dengan cara di mana objek dibuat. Mereka mengurangi kerumitan dan ketidakstabilan dengan membuat objek secara terkendali.

The baru operator sering dianggap berbahaya karena menyebarkan objek seluruh aplikasi. Seiring waktu, dapat menjadi tantangan untuk mengubah implementasi karena class menjadi sangat erat.

Pola Desain Kreasi mengatasi masalah ini dengan memisahkan klien sepenuhnya dari proses inisialisasi yang sebenarnya.

Pada artikel ini, kita akan membahas empat jenis Pola Desain Kreasi:

  1. Singleton - Memastikan bahwa paling banyak hanya satu contoh objek ada di seluruh aplikasi
  2. Metode Pabrik - Membuat objek dari beberapa kelas terkait tanpa menentukan objek yang akan dibuat
  3. Pabrik Abstrak - Menciptakan keluarga objek dependen terkait
  4. Builder - Membangun objek kompleks menggunakan pendekatan langkah demi langkah

Sekarang mari kita bahas masing-masing pola ini secara rinci.

3. Pola Desain Singleton

Pola Desain Singleton bertujuan untuk tetap memeriksa inisialisasi objek dari kelas tertentu dengan memastikan bahwa hanya satu contoh objek yang ada di seluruh Mesin Virtual Java.

Kelas Singleton juga menyediakan satu titik akses global yang unik ke objek tersebut sehingga setiap panggilan berikutnya ke titik akses hanya mengembalikan objek tertentu itu.

3.1. Contoh Pola Singleton

Meskipun pola Singleton diperkenalkan oleh GoF, implementasi asli diketahui bermasalah dalam skenario multithread.

Jadi di sini, kita akan mengikuti pendekatan yang lebih optimal yang menggunakan kelas dalam statis:

public class Singleton { private Singleton() {} private static class SingletonHolder { public static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }

Di sini, kita telah membuat kelas dalam statis yang menampung instance kelas Singleton . Ini membuat instance hanya ketika seseorang memanggil metode getInstance () dan bukan ketika kelas luar dimuat.

Ini adalah pendekatan yang banyak digunakan untuk kelas Singleton karena tidak memerlukan sinkronisasi, aman untuk thread, menerapkan inisialisasi lambat, dan memiliki boilerplate yang relatif lebih sedikit.

Juga, perhatikan bahwa konstruktor memiliki pengubah akses privat . Ini adalah persyaratan untuk membuat Singleton karena konstruktor publik berarti siapa pun dapat mengaksesnya dan mulai membuat instance baru.

Ingat, ini bukan implementasi GoF yang asli. Untuk versi aslinya, silakan kunjungi artikel Baeldung yang ditautkan ini tentang Singletons di Jawa.

3.2. Kapan Menggunakan Pola Desain Singleton

  • Untuk sumber daya yang mahal untuk dibuat (seperti objek koneksi database)
  • Ini praktik yang baik untuk mempertahankan semua penebang sebagai lajang yang meningkatkan kinerja
  • Kelas yang menyediakan akses ke pengaturan konfigurasi untuk aplikasi
  • Kelas yang berisi sumber daya yang diakses dalam mode bersama

4. Pola Desain Metode Pabrik

Pola Desain Pabrik atau Pola Desain Metode Pabrik adalah salah satu pola desain yang paling banyak digunakan di Jawa.

Menurut GoF, pola ini “mendefinisikan antarmuka untuk membuat objek, tetapi biarkan subclass memutuskan kelas mana yang akan dibuat. Metode Pabrik memungkinkan kelas menangguhkan instantiation ke subclass ”.

Pola ini mendelegasikan tanggung jawab untuk menginisialisasi kelas dari klien ke kelas pabrik tertentu dengan membuat jenis konstruktor virtual.

Untuk mencapai ini, kami mengandalkan pabrik yang memberi kami objek, menyembunyikan detail implementasi aktual. Objek yang dibuat diakses menggunakan antarmuka umum.

4.1. Contoh Pola Desain Metode Pabrik

Dalam contoh ini, kita akan membuat antarmuka Polygon yang akan diimplementasikan oleh beberapa kelas beton. Sebuah PolygonFactory akan digunakan untuk mengambil objek dari keluarga ini:

Mari pertama-tama buat antarmuka Polygon :

public interface Polygon { String getType(); }

Selanjutnya, kita akan membuat beberapa implementasi seperti Square , Triangle, dll. Yang mengimplementasikan antarmuka ini dan mengembalikan objek bertipe Polygon .

Sekarang kita dapat membuat pabrik yang menggunakan jumlah sisi sebagai argumen dan mengembalikan implementasi yang sesuai dari antarmuka ini:

public class PolygonFactory { public Polygon getPolygon(int numberOfSides) { if(numberOfSides == 3) { return new Triangle(); } if(numberOfSides == 4) { return new Square(); } if(numberOfSides == 5) { return new Pentagon(); } if(numberOfSides == 7) { return new Heptagon(); } else if(numberOfSides == 8) { return new Octagon(); } return null; } }

Perhatikan bagaimana klien dapat mengandalkan pabrik ini untuk memberi kita Polygon yang sesuai , tanpa harus menginisialisasi objek secara langsung.

4.2. Kapan Menggunakan Pola Desain Metode Pabrik

  • Ketika implementasi antarmuka atau kelas abstrak diharapkan sering berubah
  • Ketika implementasi saat ini tidak dapat mengakomodasi perubahan baru dengan nyaman
  • Ketika proses inisialisasi relatif sederhana, dan konstruktor hanya membutuhkan beberapa parameter

5. Abstract Factory Design Pattern

In the previous section, we saw how the Factory Method design pattern could be used to create objects related to a single family.

By contrast, the Abstract Factory Design Pattern is used to create families of related or dependent objects. It's also sometimes called a factory of factories.

For a detailed explanation, check out our Abstract Factory tutorial.

6. Builder Design Pattern

The Builder Design Pattern is another creational pattern designed to deal with the construction of comparatively complex objects.

When the complexity of creating object increases, the Builder pattern can separate out the instantiation process by using another object (a builder) to construct the object.

This builder can then be used to create many other similar representations using a simple step-by-step approach.

6.1. Builder Pattern Example

The original Builder Design Pattern introduced by GoF focuses on abstraction and is very good when dealing with complex objects, however, the design is a little complicated.

Joshua Bloch, in his book Effective Java, introduced an improved version of the builder pattern which is clean, highly readable (because it makes use of fluent design) and easy to use from client's perspective. In this example, we'll discuss that version.

This example has only one class, BankAccount which contains a builder as a static inner class:

public class BankAccount { private String name; private String accountNumber; private String email; private boolean newsletter; // constructors/getters public static class BankAccountBuilder { // builder code } } 

Note that all the access modifiers on the fields are declared private since we don't want outer objects to access them directly.

The constructor is also private so that only the Builder assigned to this class can access it. All of the properties set in the constructor are extracted from the builder object which we supply as an argument.

We've defined BankAccountBuilder in a static inner class:

public static class BankAccountBuilder { private String name; private String accountNumber; private String email; private boolean newsletter; public BankAccountBuilder(String name, String accountNumber) { this.name = name; this.accountNumber = accountNumber; } public BankAccountBuilder withEmail(String email) { this.email = email; return this; } public BankAccountBuilder wantNewsletter(boolean newsletter) { this.newsletter = newsletter; return this; } public BankAccount build() { return new BankAccount(this); } } 

Notice we've declared the same set of fields that the outer class contains. Any mandatory fields are required as arguments to the inner class's constructor while the remaining optional fields can be specified using the setter methods.

This implementation also supports the fluent design approach by having the setter methods return the builder object.

Finally, the build method calls the private constructor of the outer class and passes itself as the argument. The returned BankAccount will be instantiated with the parameters set by the BankAccountBuilder.

Let's see a quick example of the builder pattern in action:

BankAccount newAccount = new BankAccount .BankAccountBuilder("Jon", "22738022275") .withEmail("[email protected]") .wantNewsletter(true) .build();

6.2. When to Use Builder Pattern

  1. When the process involved in creating an object is extremely complex, with lots of mandatory and optional parameters
  2. When an increase in the number of constructor parameters leads to a large list of constructors
  3. When client expects different representations for the object that's constructed

7. Conclusion

Pada artikel ini, kita belajar tentang pola desain kreasi di Jawa. Kita juga membahas empat tipe yang berbeda, yaitu Singleton, Factory Method, Abstrak Factory dan Builder Pattern, kelebihannya, contohnya dan kapan kita harus menggunakannya.

Seperti biasa, potongan kode lengkap tersedia di GitHub.