Saya memiliki kelas yang sudah ada yang berinteraksi yang dapat membuka, membaca atau menulis ke file. Saya perlu mengambil modifikasi file untuk tujuan itu saya harus menambahkan metode baru
Misalkan berikut ini adalah definisi kelas saya di mana saya ingin menambahkan metode baru.
class IO_file
{
std::string m_file_name;
public:
IO();
IO(std::string file_name);
+ time_t get_mtime(file_name);
+ OR
+ time_t get_mtime();
};
Saya punya dua opsi -
Membuat objek kosong dan kemudian meneruskan namafile dalam argumen metode yang saya ingin mengambil waktu modifikasi file.
Lulus nama file pada konstruksi objek dan cukup panggil fungsi anggota yang akan beroperasi pada variabel anggota.
Kedua opsi akan melayani tujuan. Saya juga percaya bahwa pendekatan kedua lebih baik daripada yang pertama. Tapi yang tidak saya mengerti adalah Bagaimana ? Apakah pendekatan pertama desain yang buruk karena tidak menggunakan variabel anggota? Prinsip desain berorientasi objek mana yang dilanggar? Jika fungsi anggota tidak menggunakan variabel anggota, haruskah fungsi anggota itu selalu dibuat statis?
IO("somefile.txt").get_mtime("someotherfile.txt")
. Apa artinya itu?Jawaban:
Tidak.
OOP tidak peduli jika fungsi anggota Anda menggunakan, atau tidak menggunakan, properti kelas atau variabel anggota. OOP peduli tentang polimorfisme dan bukan implementasi hard coding. Fungsi statis memiliki kegunaannya tetapi fungsi tidak boleh statis hanya karena tidak bergantung pada keadaan objek. Jika itu pemikiran Anda baik-baik saja, tetapi jangan menyalahkan OOP karena ide itu tidak berasal dari OOP.
Jika Anda tidak perlu mengingat status dari panggilan ke panggilan, tidak ada alasan untuk menggunakan status tersebut.
Tidak ada
Tidak. Pemikiran ini memiliki implikasi panah menuju ke arah yang salah.
Fungsi statis tidak dapat mengakses keadaan instance
Jika fungsi tidak perlu mengakses keadaan instance maka fungsi tersebut bisa statis atau non-statis
Menjadikan fungsi ini statis di sini sepenuhnya terserah Anda. Tapi itu akan membuatnya lebih seperti global jika Anda melakukannya. Sebelum menjadi statis, pertimbangkan untuk menjalankan fungsi di kelas tanpa kewarganegaraan. Ini lebih fleksibel.
Di sini saya memiliki contoh OOP dari fungsi anggota yang tidak menggunakan properti kelas atau variabel anggota.
Fungsi anggota (dan ini adalah kelas tanpa kewarganegaraan) :
Tiga implementasi yang berbeda:
Tempat menyimpan pilihan implementasi:
Contoh penggunaan
Output:
Dan semua tanpa
execute()
mempedulikan keadaan objek apa pun. TheStrategy
kelas sebenarnya stateless. Hanya status dalamContext
. Objek stateless sangat baik di OOP.Ditemukan kode ini di sini .
sumber
get_mtime
akan lebih masuk akal di sini sebagai fungsi mandiri atau sebagaistatic
fungsi, daripada seperti yang Anda tunjukkan di sini.The
mtime
file dibaca, pada kebanyakan sistem, dari panggilan kelstat
atau serupa, dan tidak memerlukan file descriptor terbuka, sehingga tidak masuk akal untuk memilikinya sebagai fungsi anggota dari kelas instantiated.sumber
static
anggota.Alasan bahwa opsi kedua tampaknya secara naluriah lebih baik (dan, IMO, IS lebih baik) adalah karena opsi pertama Anda memberi Anda objek yang sebenarnya tidak mewakili apa pun.
Dengan tidak menentukan nama file, kelas IO_file Anda benar-benar hanya sebuah objek abstrak yang kebetulan menyerupai file konkret. Jika Anda memasukkan nama file ketika Anda memanggil metode, Anda mungkin juga hanya refactor seluruh metode menjadi fungsi murni mengambang bebas sebagai gantinya; tidak ada manfaat sebenarnya untuk menjaganya terikat dengan objek yang Anda perlukan untuk instantiate hanya untuk menggunakannya. Itu hanya fungsi; pelat objek objek hanya langkah tambahan yang tidak nyaman.
Di sisi lain, setelah nama file diberikan metode apa pun yang Anda panggil pada objek yang sedang seperti pertanyaan tentang contoh tertentu dari suatu hal. Itu lebih baik OO karena objek Anda memiliki makna aktual dan, karenanya, utilitas.
sumber
Mari kita terjemahkan ini ke C. Pertama kita kelas kita - sekarang ini sebuah struct:
Mari, untuk kesederhanaan cuplikan, tentukan fungsi konstruktor (mengabaikan kebocoran memori untuk saat ini):
Opsi # 2 terlihat seperti ini:
dan digunakan seperti ini:
Bagaimana dengan opsi # 1? Yah, kelihatannya seperti ini:
Dan bagaimana ini digunakan? Pada dasarnya, Anda meminta untuk membuang sampah sebagai parameter pertama:
Tidak masuk akal, bukan?
Sistem objek C ++ menyembunyikannya, tetapi objek tersebut juga merupakan argumen dari metode - argumen pointer implisit bernama
this
. Ini adalah pilihan # 1 yang buruk - ia memiliki argumen yang tidak digunakan oleh definisi (argumen yang kebetulan tidak digunakan, tetapi dapat digunakan dalam penggantian OK). Argumen semacam itu tidak memberikan kontribusi apa pun saat menyulitkan tanda tangan, definisi, dan penggunaan fungsi serta membingungkan pembaca kode yang dibiarkan merenungkan apa yang seharusnya dilakukan oleh argumen, mengapa boleh saja membuang sampah ke dalamnya, dan terlepas dari kenyataan bahwa Anda atau tidak. meneruskan objek sampah /NULL
/ kosong ke sana adalah penyebab bug yang mereka coba selesaikan. Spoiler - tidak, tetapi mereka masih akan membuang waktu mengeksplorasi kemungkinan itu.Fakta bahwa argumen sampah implisit dapat mengurangi efeknya, tetapi masih ada, dan dan mudah dihindari dengan membuat metode
static
.sumber