Bisakah mengubah nama metode mempertahankan enkapsulasi?

9

Saya membaca halaman ini , tentang kapan getter / setter dibenarkan, dan OP memberikan contoh kode berikut:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

The diterima Jawaban negara:

By the way, dalam contoh Anda, saya akan memberikan kelas Fridgeyang putCheese()dan takeCheese()metode, bukan get_cheese() dan set_cheese(). Maka Anda masih akan memiliki enkapsulasi.

Bagaimana enkapsulasi dipertahankan dengan mengganti nama dari get / set ke putCheese()/ takeCheese()Anda jelas mendapatkan / menetapkan nilai, jadi mengapa tidak meninggalkannya sebagai get / set?

Dalam jawaban yang sama juga disebutkan:

Memiliki getter dan setter tidak dengan sendirinya merusak enkapsulasi. Apa yang memecahkan enkapsulasi secara otomatis menambahkan pengambil dan penyetel untuk setiap anggota data (setiap bidang, dalam istilah java), tanpa memikirkannya.

Dalam hal ini, kami hanya memiliki satu variabel,, cheesedan Anda mungkin ingin mengambil dan mengembalikan keju ke lemari es, sehingga pasangan get / set dalam kasus ini dibenarkan.

QueenSvetlana
sumber
7
putCheeseakan menambahkan keju ke lemari es, dan takeCheeseakan menghapusnya - ini adalah abstraksi berorientasi domain (tingkat lebih tinggi), bukan pengambil & setter bidang objek (yang merupakan abstraksi pemrograman komputer level rendah).
Erik Eidt

Jawaban:

17

Saya pikir kamu melewatkan intinya. Itu tidak mengatakan Anda harus mengganti nama setter dan pengambil, tetapi memiliki metode yang menambah dan menghapus item dari lemari es. yaitu

public class Fridge
{
    private int numberOfCheeseSlices;

    public void AddCheeseSlices(int n)
    {
         if(n < 0) { 
             throw new Exception("you cant add negative cheese!");
         }
         if(numberOfCheeseSlices + n > this.capacityOfFridge) { 
             throw new Exception("TOO MUCH CHEESE!!");
         }
         ..etc
         this.numberOfCheeseSlices += n;
    }
}

Sekarang variabel pribadi dienkapsulasi. Saya tidak bisa hanya mengaturnya untuk apa pun yang saya inginkan, saya hanya bisa menambah dan menghapus irisan keju dari kulkas menggunakan metode, yang pada gilirannya memastikan bahwa aturan logika bisnis keju apa pun yang saya inginkan diterapkan.

Ewan
sumber
2
Benar, tetapi Anda masih bisa membiarkannya karena setCheese()memiliki logika yang sama di setter. Bagi saya, Anda berusaha menyembunyikan fakta bahwa Anda menggunakan setter dengan mengganti nama metode, tetapi jelas pengambil / pengaturan sesuatu.
QueenSvetlana
21
@QueenSvetlana itu bukan setter. Ini operasi. Anda memberi tahu kulkas "ini keju lain," dan menambahkannya ke dalam jumlah keju enkapsulasi internal. Seorang setter akan berkata "Anda sekarang memiliki 5 keju." Ini adalah operasi yang berbeda secara fungsional, bukan hanya nama yang berbeda.
Semut
1
Anda bisa menyebutnya setCheese, tetapi itu akan membingungkan karena tidak akan menetapkan nilai keju.
Ewan
6
Perhatikan ada bug integer overflow di sini. Jika sudah ada lebih dari 0 keju, AddCheese(Integer.MAX_VALUE)seharusnya gagal, tetapi tidak akan.
user253751
3
yang akan dibahas dalam bagian ..etc
Ewan
5

Getters dan setters memecah enkapsulasi setiap saat , menurut definisi. Yang mungkin diperdebatkan adalah bahwa kadang-kadang kita perlu melakukan itu. Dengan hal itu, inilah jawaban saya:

Bagaimana enkapsulasi dipertahankan dengan mengganti nama dari get / set ke putCheese () / takeCheese () Anda jelas mendapatkan / menetapkan nilai, jadi mengapa tidak meninggalkannya sebagai get / set?

Perbedaannya adalah dalam semantik, yaitu makna dari apa yang Anda tulis. Enkapsulasi tidak hanya tentang melindungi, tetapi menyembunyikan kondisi internal. Keadaan internal seharusnya tidak diketahui di luar, sebaliknya objek diharapkan untuk menawarkan metode yang relevan dengan bisnis (kadang-kadang disebut sebagai "perilaku") untuk memanipulasi / menggunakan keadaan itu.

Jadi getdan setmerupakan istilah teknis dan tampaknya tidak ada hubungannya dengan domain "kulkas", sementara putdan takemungkin benar-benar masuk akal.

Namun , apakah putatau takemembuat yang sebenarnya akal masih tergantung pada persyaratan dan tidak dapat secara obyektif dinilai. Lihat poin selanjutnya:

Dalam hal ini, kami hanya memiliki satu variabel, keju, dan Anda mungkin ingin mengambil dan mengembalikan keju ke lemari es, sehingga pasangan get / set dalam kasus ini dibenarkan.

Itu tidak dapat ditentukan secara objektif tanpa lebih banyak konteks. Contoh Anda berisi go_shopping()metode di tempat lain. Jika itu untuk apa Fridge, daripada tidak perlu getatau set, apa yang dibutuhkan Fridge.go_shopping(). Dengan cara ini Anda memiliki metode yang berasal dari persyaratan, semua "data" yang dibutuhkan adalah lokal dan Anda memiliki perilaku aktual, bukan hanya struktur data terselubung.

Ingat, Anda tidak membangun generik, dapat digunakan kembali Fridge. Anda sedang membangun Fridgeuntuk kebutuhan Anda saja. Upaya apa pun yang dihabiskan untuk membuatnya lebih dari yang seharusnya sebenarnya sia-sia.

Robert Bräutigam
sumber
10
Getters and setters break encapsulation every single time- Itu agak terlalu kuat untuk seleraku. Metode (termasuk getter dan setter) memiliki tujuan yang sama seperti gerbang di konser: mereka memungkinkan masuk dan keluar teratur dari tempat tersebut.
Robert Harvey
8
"Getters dan setters memecah enkapsulasi setiap saat, menurut definisi" - dengan definisi apa? Saya juga punya masalah dengan ini, karena getter dan setter hanya bagian dari antarmuka publik, seperti anggota publik lainnya; mereka hanya memecahkan enkapsulasi jika mereka mengekspos detail implementasi yang dianggap internal oleh desain (yaitu, dengan keputusan programmer (atau tim)). Fakta bahwa getter dan setter sering ditambahkan secara sembarangan, dengan kontrol kopling menjadi renungan, adalah masalah lain sepenuhnya.
Filip Milovanović
2
@ FilipMilovanović Titik adil. Seperti yang saya sebutkan dalam jawaban, "enkapsulasi" digunakan untuk menyembunyikan objek internal (== objek keadaan == variabel instan). Getters dan setter mempublikasikan objek internal. Oleh karena itu dengan definisi ini mereka berada dalam konflik abadi. Sekarang, apakah kadang-kadang kita perlu memecah enkapsulasi adalah masalah yang berbeda, yang harus ditangani secara terpisah. Untuk menjadi jelas, dengan mengatakan bahwa setter / getter selalu memecahkan enkapsulasi, saya tidak mengatakan itu selalu "salah", jika itu membantu.
Robert Bräutigam
5
getter dan setter tidak "memecah enkapsulasi secara harfiah selalu". Getters dan setter sering bahkan tidak merujuk ke anggota di bawahnya secara langsung, melakukan semacam operasi, atau hanya ditentukan secara eksklusif, Anda mungkin hanya memiliki pengambil atau mungkin hanya memiliki setter. Ini memecah enkapsulasi ketika getter dan setter tidak melakukan apa pun selain akses anggota dan keduanya ditentukan untuk bidang yang sama. Bahkan ini mungkin diperlukan untuk pengelola perpustakaan yang tidak ingin memecah ABI / API dengan perubahan internal dan menghindari kompilasi ulang klien.
whn
4
Ok, getter dan setter hanya memecah enkapsulasi 99% dari waktu. Senang? Dan, dengan mengekspos jenis objek yang dienkapsulasi, mereka pasti memecah enkapsulasi. Begitu Anda memilikinya public int getFoo(), hampir tidak mungkin, dalam praktiknya, untuk berubah ke tipe lain.
user949300
3

Hampir semua ini menunjukkan kesalahpahaman mendasar tentang enkapsulasi, dan bagaimana itu berlaku.

Respons awal yang Anda hancurkan adalah enkapsulasi. Aplikasi Anda mungkin memiliki kebutuhan untuk hanya mengatur nilai keju di lemari es daripada kenaikan / penurunan atau menambah / menghapus. Selain itu, ini bukan semantik, tidak peduli bagaimana Anda menyebutnya, jika Anda memiliki kebutuhan untuk mengakses dan / atau mengubah atribut Anda tidak merusak enkapsulasi dengan menyediakannya. Akhirnya, enkapsulasi tidak benar-benar tentang "bersembunyi", ini tentang mengendalikan akses ke negara dan nilai-nilai yang tidak perlu dipublikasikan atau dimanipulasi di luar kelas, sementara memberikannya kepada orang-orang yang seharusnya dan melakukan tugas yang disediakan secara internal.

Seorang pengambil atau penyetel tidak memecah enkapsulasi ketika ada kebutuhan sah untuk mendapatkan atau menetapkan nilai. Inilah sebabnya mengapa metode dapat dipublikasikan.

Enkapsulasi adalah tentang menyimpan data dan metode yang memodifikasi data secara langsung bersama di satu tempat logis, kelas.

Dalam kasus khusus ini, jelas ada kebutuhan untuk mengubah nilai keju dalam aplikasi. Terlepas dari bagaimana hal ini dilakukan, melalui get / set atau tambah / hapus, selama metode dienkapsulasi di kelas Anda mengikuti gaya berorientasi objek.

Untuk klarifikasi, saya akan memberikan contoh bagaimana enkapsulasi dipecah dengan menyediakan akses terlepas dari nama metode atau eksekusi logis.

Katakanlah lemari es Anda memiliki "masa hidup", hanya beberapa kutu sebelum lemari es tidak lagi beroperasi (demi argumen, kulkas tidak dapat diperbaiki). Secara logis tidak ada cara pengguna (atau sisa aplikasi Anda) harus dapat mengubah nilai ini. Itu harus pribadi. Itu hanya akan terlihat melalui mengatakan atribut publik yang berbeda yang dikenal sebagai "isWorking". Ketika masa hidup berakhir, secara internal set kulkas bekerja dengan palsu.

Pelaksanaan menghitung mundur seumur hidup dan membalik saklar isWorking semua internal ke lemari es, tidak ada yang di luar bisa / harus dapat mempengaruhi proses. isWorking seharusnya hanya terlihat, sehingga pengambil tidak merusak enkapsulasi. Namun menambahkan pengakses untuk elemen proses seumur hidup akan merusak enkapsulasi Anda.

Seperti kebanyakan hal, definisi enkapsulasi tidak literal, itu relatif. Apakah Anda dapat melihat X di luar kelas? Apakah Anda dapat mengubah Y? Apakah semua yang berlaku untuk objek Anda di sini di kelas ini atau apakah fungsinya tersebar di beberapa kelas?

pengguna343330
sumber
Mari kita melihatnya secara pragmatis. Anda mengatakan enkapsulasi tidak rusak jika kode dimaksudkan seperti itu, atau jika ada alasan "sah". Itu pada dasarnya berarti kita tidak pernah bisa mengatakan enkapsulasi rusak, karena pengembang hanya harus mengatakan dia "bermaksud" seperti itu, atau ada alasan "sah". Jadi definisi ini pada dasarnya tidak berguna, bukan?
Robert Bräutigam
Tidak, saya katakan enkapsulasi tidak rusak hanya dengan menyediakan akses. Dan itu tidak ada hubungannya dengan apa yang dikatakan seorang programmer, tetapi apa kebutuhan aplikasi tersebut. Aplikasi perlu memiliki akses untuk memanipulasi objek, enkapsulasi adalah tentang pengontrolan akses. Aplikasi mungkin perlu "mengatur" atribut suatu objek, tetapi logika dan atau perhitungan yang diperlukan untuk melakukan operasi "set" itu harus dienkapsulasi dalam kelas objek.
user343330
Saya pikir ini adalah di mana kami secara fundamental berbeda, Anda mengatakan: "Aplikasi mungkin perlu" mengatur "atribut objek ...". Saya kira tidak. Memilih desain yang melibatkan pengaturan atau mendapatkan atribut terserah pengembang. Itu pilihan! Ada banyak cara untuk mengkodekan sesuatu, tidak semuanya melibatkan pengambilan atau pengaturan nilai variabel instan.
Robert Bräutigam
Bisa jadi ... Biasanya desain didasarkan pada pertemuan kebutuhan, apakah salah satu dipilih oleh programmer didasarkan pada lingkungan bisnis. Namun dalam kedua kasus, jika aplikasi memiliki kebutuhan mendasar untuk memanipulasi nilai yang merupakan bagian dari objek, maka Anda harus membuat fungsionalitas itu dapat diakses dengan cara tertentu. Menyediakan titik masuk untuk melakukan pekerjaan tidak melanggar enkapsulasi. Ambil aplikasi penjualan. Di beberapa titik transaksi Anda harus menghitung pajak, melakukan hal itu di objek transaksi akan tetap dikemas, tetapi aplikasi harus mampu negara transaction.CalcTax
user343330
Setter adalah contoh buruk karena kesederhanaannya, pikirkan dalam hal fungsi yang jauh lebih berfungsi yang menghasilkan atribut objek yang diperbarui vs sesuatu di luar kelas yang melakukan pekerjaan dan kemudian mengatakan objek.attribut = x. Yang pertama adalah enkapsulasi yang baik sambil memberikan akses yang sesuai, yang kedua tidak. Sedangkan untuk getter, apakah aplikasi perlu tahu hanya sepotong objek untuk melakukan sesuatu yang lain yang tidak dapat terkandung dalam kelas objek? jika ya, mengeksposnya tidak merusak enkapsulasi Anda. jika tidak, maka enkapsulasi dalam kelas objek
user343330
1

Bukan hanya mengubah nama metode. Dua metode berfungsi secara berbeda.

(Bayangkan ini di pikiran Anda)

get_cheese dan set_cheese memperlihatkan keju. putCheese () dan takeCheese () menjaga keju tetap tersembunyi dan mengurusnya serta memberi pengguna cara untuk menanganinya. Pengamat tidak melihat keju, ia hanya melihat dua metode memanipulasinya.

Daneesha
sumber