Pertanyaan Mengapa menggunakan getter dan setter / accessors? [Tutup]


Apa keuntungan menggunakan getter dan setter - yang hanya mendapatkan dan mengatur - daripada hanya menggunakan kolom publik untuk variabel-variabel itu?

Jika getter dan setter pernah melakukan lebih dari sekadar get / set sederhana, saya bisa mengetahui yang ini dengan sangat cepat, tetapi saya tidak 100% jelas tentang bagaimana:

public String foo;

lebih buruk dari:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Sedangkan yang pertama membutuhkan kode boilerplate yang jauh lebih sedikit.


1303
2017-10-14 18:20


asal


Jawaban:


Sebenarnya ada banyak alasan bagus untuk mempertimbangkan menggunakan akseptor daripada langsung mengekspos bidang kelas - hanya argumen enkapsulasi dan membuat perubahan di masa depan lebih mudah.

Inilah beberapa alasan yang saya ketahui:

  • Enkapsulasi perilaku yang terkait dengan mendapatkan atau mengatur properti - ini memungkinkan fungsionalitas tambahan (seperti validasi) untuk ditambahkan lebih mudah nanti.
  • Menyembunyikan representasi internal properti sambil memaparkan properti menggunakan representasi alternatif.
  • Isolasi antarmuka publik Anda dari perubahan - memungkinkan antarmuka publik tetap konstan sementara penerapan berubah tanpa memengaruhi konsumen yang sudah ada.
  • Mengontrol masa hidup dan manajemen memori (pembuangan) semantik properti - terutama penting dalam lingkungan memori yang tidak dikelola (seperti C ++ atau Objective-C).
  • Menyediakan titik intersepsi debugging ketika sebuah properti berubah saat runtime - debugging kapan dan di mana properti berubah ke nilai tertentu bisa sangat sulit tanpa ini dalam beberapa bahasa.
  • Peningkatan interoperabilitas dengan pustaka yang dirancang untuk beroperasi melawan pengambil properti / setter - Mocking, Serialization, dan WPF muncul dalam pikiran.
  • Memungkinkan pewaris untuk mengubah semantik tentang bagaimana properti berperilaku dan diekspos dengan mengesampingkan metode pengambil / penyetel.
  • Mengizinkan pengambil / penyetel untuk diedarkan sebagai ekspresi lambda alih-alih nilai.
  • Getters dan setter dapat memungkinkan tingkat akses yang berbeda - misalnya get mungkin publik, tetapi set bisa dilindungi.

794
2017-10-14 18:47



Karena 2 minggu (bulan, tahun) dari sekarang ketika Anda menyadari bahwa setter Anda perlu melakukan lebih daripada hanya mengatur nilainya, Anda juga akan menyadari bahwa properti telah digunakan langsung di 238 kelas lain :-)


389
2017-10-14 18:23



Bidang publik tidak lebih buruk daripada pasangan pengambil / penyetel yang tidak melakukan apa pun kecuali mengembalikan bidang dan menugaskannya. Pertama, jelas bahwa (dalam sebagian besar bahasa) tidak ada perbedaan fungsional. Perbedaan apa pun harus dalam faktor lain, seperti pemeliharaan atau keterbacaan.

Keuntungan yang sering disebut dari pasangan pengambil / penyetel, tidak. Ada klaim ini bahwa Anda dapat mengubah implementasi dan klien Anda tidak perlu dikompilasi ulang. Seharusnya, setter membiarkan Anda menambahkan fungsi seperti validasi nanti dan klien Anda bahkan tidak perlu mengetahuinya. Namun, menambahkan validasi ke penyetel adalah perubahan pada prasyaratnya, pelanggaran kontrak sebelumnya, yang, cukup sederhana, "Anda dapat memasukkan apa pun ke sini, dan Anda bisa mendapatkan hal yang sama nanti dari pengambil".

Jadi, sekarang Anda melanggar kontrak, mengubah setiap file dalam basis kode adalah sesuatu yang harus Anda lakukan, bukan hindari. Jika Anda menghindarinya, Anda membuat asumsi bahwa semua kode mengasumsikan bahwa kontrak untuk metode itu berbeda.

Jika itu tidak seharusnya kontrak, maka antarmuka itu memungkinkan klien untuk menempatkan objek dalam keadaan yang tidak valid. Itu kebalikan dari enkapsulasi Jika bidang itu tidak dapat benar-benar disetel dari awal, mengapa tidak validasi di sana sejak awal?

Argumen yang sama ini berlaku untuk keuntungan lain dari pasangan pengambil / penyetel pass-through: jika nanti Anda memutuskan untuk mengubah nilai yang ditetapkan, Anda melanggar kontrak. Jika Anda mengganti fungsi default di kelas turunan, dengan cara di luar beberapa modifikasi yang tidak berbahaya (seperti penebangan atau perilaku yang tidak dapat diamati lainnya), Anda melanggar kontrak kelas dasar. Itu adalah pelanggaran Prinsip Pengganti Liskov, yang dilihat sebagai salah satu prinsip OO.

Jika sebuah kelas memiliki getter bodoh dan setter untuk setiap bidang, maka itu adalah kelas yang tidak memiliki invarian sama sekali, tidak ada kontrak. Apakah itu benar-benar desain berorientasi objek? Jika semua kelas memiliki orang-orang yang getter dan setter, itu hanya pemegang data bodoh, dan pemegang data bodoh harus terlihat seperti pemegang data bodoh:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Menambahkan pass-through pengambil / setter pair ke kelas seperti itu tidak menambah nilai. Kelas-kelas lain harus menyediakan operasi yang berarti, bukan hanya operasi yang telah disediakan oleh bidang. Begitulah cara Anda mendefinisikan dan mempertahankan invariants yang bermanfaat.

Klien: "Apa yang bisa saya lakukan dengan objek kelas ini?"
Perancang: "Anda dapat membaca dan menulis beberapa variabel."
Klien: "Oh ... keren, saya kira?"

Ada alasan untuk menggunakan getter dan setter, tetapi jika alasan tersebut tidak ada, membuat pasangan pengambil / penyetel dalam nama dewa enkapsulasi palsu bukanlah hal yang baik. Alasan yang sah untuk membuat getter atau setter termasuk hal-hal yang sering disebutkan sebagai perubahan potensial yang dapat Anda buat nanti, seperti validasi atau representasi internal yang berbeda. Atau mungkin nilainya harus dapat dibaca oleh klien tetapi tidak dapat ditulis (misalnya, membaca ukuran kamus), jadi pengambil yang sederhana adalah pilihan yang bagus. Tetapi alasan itu harus ada ketika Anda membuat pilihan, dan bukan hanya sebagai hal potensial yang mungkin Anda inginkan nantinya. Ini adalah contoh dari YAGNI (Anda Tidak Akan Membutuhkannya).


307
2017-08-24 10:55



Banyak orang berbicara tentang kelebihan getter dan setter tapi saya ingin bermain sebagai pengacara setan. Saat ini saya sedang men-debug sebuah program yang sangat besar di mana para programmer memutuskan untuk membuat semua getter dan setter. Itu mungkin tampak bagus, tetapi mimpi buruk rekayasa baliknya.

Katakanlah Anda melihat ratusan baris kode dan Anda menemukan ini:

person.name = "Joe";

Ini adalah potongan kode yang indah sampai Anda menyadari bahwa itu adalah setter. Sekarang, Anda mengikuti penyetel itu dan menemukan bahwa itu juga menetapkan person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName, dan memanggil person.update (), yang mengirim kueri ke database, dll. Oh, itu di mana kebocoran memori Anda terjadi.

Memahami potongan kode lokal pada pandangan pertama adalah properti penting dari keterbacaan yang baik bahwa getter dan setter cenderung rusak. Itulah mengapa saya mencoba menghindarinya ketika saya bisa, dan meminimalkan apa yang mereka lakukan ketika saya menggunakannya.


75
2017-10-14 21:00



Ada banyak alasan. Salah satu favorit saya adalah ketika Anda perlu mengubah perilaku atau mengatur apa yang dapat Anda atur pada variabel. Misalnya, katakanlah Anda memiliki metode setSpeed ​​(int speed). Tetapi Anda ingin agar Anda hanya dapat mengatur kecepatan maksimum 100. Anda akan melakukan sesuatu seperti:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Sekarang bagaimana jika SETIAP MANAPUN di kode Anda, Anda menggunakan bidang publik dan kemudian Anda menyadari bahwa Anda memerlukan persyaratan di atas? Bersenang-senang memburu setiap penggunaan bidang publik, bukan hanya memodifikasi penyetel Anda.

2 sen saya :)


43
2017-10-14 18:27



Dalam dunia yang berorientasi objek murni getter dan setter adalah a anti-pola yang mengerikan. Baca artikel ini: Getters / Setters. Jahat. Periode. Singkatnya, mereka mendorong pemrogram untuk berpikir tentang objek sebagai struktur data, dan jenis pemikiran ini murni prosedural (seperti di COBOL atau C). Dalam bahasa berorientasi objek tidak ada struktur data, tetapi hanya objek yang mengekspos perilaku (bukan atribut / properti!)

Anda dapat menemukan lebih banyak tentang mereka di Bagian 3.5 dari Benda-benda Elegan (buku saya tentang pemrograman berorientasi objek).


43
2017-09-23 16:39



Salah satu keuntungan dari aksesor dan mutator adalah Anda dapat melakukan validasi.

Misalnya, jika foo bersifat publik, saya dapat dengan mudah mengaturnya null dan kemudian orang lain bisa mencoba memanggil metode pada objek. Tapi sudah tidak ada lagi! Dengan setFoo metode, saya bisa memastikan itu foo tidak pernah diatur null.

Aksesor dan peretas juga memungkinkan enkapsulasi - jika Anda tidak seharusnya melihat nilainya setelah pengaturannya (mungkin itu ditetapkan dalam konstruktor dan kemudian digunakan dengan metode, tetapi tidak pernah seharusnya diubah), itu tidak akan pernah dilihat oleh siapa pun. Tetapi jika Anda dapat mengizinkan kelas lain untuk melihat atau mengubahnya, Anda dapat memberikan accessor dan / atau mutator yang tepat.


36
2017-10-14 18:25