Saya baru-baru ini mulai membaca Java Efektif oleh Joshua Bloch. Saya menemukan ide tentang pola Builder [Item 2 dalam buku] sangat menarik. Saya mencoba menerapkannya dalam proyek saya tetapi ada kesalahan kompilasi. Berikut adalah intinya apa yang saya coba lakukan:
Kelas dengan banyak atribut dan kelas pembangunnya:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
Kelas tempat saya mencoba menggunakan kelas di atas:
public class Main {
public static void main(String args[]) {
NutritionalFacts n =
new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
}
}
Saya mendapatkan kesalahan kompiler berikut:
instans penutup yang berisi effectivejava.BuilderPattern.NutritionalFacts.Builder diperlukan NutritionalFacts n = new NutritionalFacts.Builder (10) .carbo (23) .fat (1) .build ();
Saya tidak mengerti apa arti pesan itu. Tolong jelaskan. Kode di atas mirip dengan contoh yang disarankan oleh Bloch dalam bukunya.
java
design-patterns
builder-pattern
Swaranga Sarma
sumber
sumber
Jawaban:
Jadikan pembangun itu
static
kelas. Maka itu akan berhasil. Jika non-statis, itu akan membutuhkan sebuah instance dari kelasnya sendiri - dan intinya bukanlah untuk memiliki sebuah instance, dan bahkan untuk melarang membuat instance tanpa pembangun.public class NutritionFacts { public static class Builder { } }
Referensi: Kelas bertingkat
sumber
Builder
adastatic
di contoh di buku (halaman 14, baris 10 di Edisi ke-2).Anda harus menjadikan kelas Builder sebagai statis dan Anda juga harus membuat kolom menjadi final dan memiliki getter untuk mendapatkan nilai tersebut. Jangan berikan penyetel untuk nilai-nilai itu. Dengan cara ini kelas Anda tidak akan pernah berubah.
public class NutritionalFacts { private final int sodium; private final int fat; private final int carbo; public int getSodium(){ return sodium; } public int getFat(){ return fat; } public int getCarbo(){ return carbo; } public static class Builder { private int sodium; private int fat; private int carbo; public Builder sodium(int s) { this.sodium = s; return this; } public Builder fat(int f) { this.fat = f; return this; } public Builder carbo(int c) { this.carbo = c; return this; } public NutritionalFacts build() { return new NutritionalFacts(this); } } private NutritionalFacts(Builder b) { this.sodium = b.sodium; this.fat = b.fat; this.carbo = b.carbo; } }
Dan sekarang Anda dapat mengatur properti sebagai berikut:
NutritionalFacts n = new NutritionalFacts.Builder().sodium(10).carbo(15). fat(5).build();
sumber
final
bidang masuk akal hanya jika bidang selalu dibutuhkan selama inisialisasi. Jika tidak, maka bidang tidak seharusnyafinal
.Untuk menghasilkan pembangun dalam di Intellij IDEA, lihat plugin ini: https://github.com/analytically/innerbuilder
sumber
Anda mencoba mengakses kelas non-statis dengan cara statis. Ubah
Builder
kestatic class Builder
dan itu harus berhasil.Penggunaan contoh yang Anda berikan gagal karena tidak ada contoh
Builder
saat ini. Kelas statis untuk semua tujuan praktis selalu dibuat. Jika Anda tidak membuatnya statis, Anda perlu mengatakan:Widget = new Widget.Builder(10).setparm1(1).setparm2(3).build();
Karena Anda perlu membangun yang baru
Builder
setiap saat.sumber
Anda perlu mendeklarasikan
Builder
kelas dalam sebagaistatic
.Lihat beberapa dokumentasi untuk kelas dalam non-statis dan kelas dalam statis .
Pada dasarnya instance kelas dalam non-statis tidak dapat ada tanpa instance kelas luar yang dilampirkan.
sumber
Setelah Anda mendapatkan ide, dalam praktiknya, Anda mungkin akan merasa lombok
@Builder
jauh lebih nyaman.@Builder
memungkinkan Anda secara otomatis menghasilkan kode yang diperlukan agar kelas Anda dapat digunakan dengan kode seperti:Person.builder() .name("Adam Savage") .city("San Francisco") .job("Mythbusters") .job("Unchained Reaction") .build();
Dokumentasi resmi: https://www.projectlombok.org/features/Builder
sumber
Ini berarti Anda tidak dapat membuat tipe lampiran. Ini berarti bahwa pertama-tama Anda harus membuat instance kelas "induk", lalu dari instance ini Anda dapat membuat instance kelas bersarang.
NutritionalFacts n = new NutritionalFacts() Builder b = new n.Builder(10).carbo(23).fat(1).build();
Kelas Bersarang
sumber
Kelas Builder harus statis. Saya tidak punya waktu sekarang untuk benar-benar menguji kode di luar itu, tetapi jika tidak berhasil, beri tahu saya dan saya akan melihatnya lagi.
sumber
Saya pribadi lebih suka menggunakan pendekatan lain, bila Anda memiliki 2 kelas yang berbeda. Jadi, Anda tidak memerlukan kelas statis apa pun. Ini pada dasarnya untuk menghindari penulisan
Class.Builder
saat Anda harus membuat instance baru.public class Person { private String attr1; private String attr2; private String attr3; // package access Person(PersonBuilder builder) { this.attr1 = builder.getAttr1(); // ... } // ... // getters and setters } public class PersonBuilder ( private String attr1; private String attr2; private String attr3; // constructor with required attribute public PersonBuilder(String attr1) { this.attr1 = attr1; } public PersonBuilder setAttr2(String attr2) { this.attr2 = attr2; return this; } public PersonBuilder setAttr3(String attr3) { this.attr3 = attr3; return this; } public Person build() { return new Person(this); } // .... }
Jadi, Anda dapat menggunakan pembangun Anda seperti ini:
Person person = new PersonBuilder("attr1") .setAttr2("attr2") .build();
sumber
Seperti yang telah disebutkan di sini, Anda perlu membuat kelas
static
. Hanya tambahan kecil - jika Anda mau, ada cara yang sedikit berbeda tanpa statis.Pertimbangkan ini. Mengimplementasikan pembangun dengan mendeklarasikan sesuatu seperti
withProperty(value)
penyetel tipe di dalam kelas dan membuatnya mengembalikan referensi ke dirinya sendiri. Dalam pendekatan ini, Anda memiliki kelas tunggal dan elegan yang merupakan thread yang aman dan ringkas.Pertimbangkan ini:
public class DataObject { private String first; private String second; private String third; public String getFirst(){ return first; } public void setFirst(String first){ this.first = first; } ... public DataObject withFirst(String first){ this.first = first; return this; } public DataObject withSecond(String second){ this.second = second; return this; } public DataObject withThird(String third){ this.third = third; return this; } } DataObject dataObject = new DataObject() .withFirst("first data") .withSecond("second data") .withThird("third data");
Lihat untuk contoh Java Builder lainnya.
sumber
Anda perlu mengubah kelas Builder menjadi kelas statis Builder . Maka itu akan bekerja dengan baik.
sumber