Apakah kelebihan contoh prinsip Terbuka / tertutup?

12

Wikipedia mengatakan

"entitas perangkat lunak (kelas, modul, fungsi, dll.) harus terbuka untuk ekstensi, tetapi ditutup untuk modifikasi"

Kata fungsi menarik perhatian saya, dan sekarang saya bertanya-tanya apakah kita dapat berasumsi bahwa menciptakan kelebihan untuk suatu metode dapat dianggap sebagai contoh prinsip Terbuka / tertutup atau tidak?

Izinkan saya menjelaskan sebuah contoh. Pertimbangkan bahwa Anda memiliki metode di lapisan layanan Anda, yang digunakan di hampir 1000 tempat. Metode ini mendapatkan userId dan menentukan apakah pengguna adalah admin atau tidak:

bool IsAdmin(userId)

Sekarang pertimbangkan bahwa di suatu tempat itu perlu untuk menentukan apakah pengguna adalah admin atau tidak, berdasarkan nama pengguna, bukan userId. Jika kami mengubah tanda tangan dari metode yang disebutkan di atas, maka kami telah memecahkan kode di 1000 tempat (fungsi harus ditutup untuk modifikasi). Dengan demikian kita dapat membuat kelebihan untuk mendapatkan nama pengguna, menemukan userId berdasarkan nama pengguna, dan metode asli:

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

Dengan cara ini, kami telah memperluas fungsi kami melalui membuat kelebihan untuk itu (fungsi harus terbuka untuk ekstensi).

Apakah ini contoh prinsip Terbuka / tertutup?

Saeed Neamati
sumber

Jawaban:

5

Saya pribadi akan menafsirkan pernyataan wiki sebagai berikut:

  • untuk kelas: jangan ragu untuk mewarisi kelas dan menimpa atau memperluas fungsinya, tetapi jangan meretas kelas asli sehingga mengubah apa yang dilakukannya.
  • untuk modul (mungkin perpustakaan misalnya): jangan ragu untuk menulis modul / perpustakaan baru yang membungkus aslinya, menggabungkan fungsi menjadi versi yang lebih mudah digunakan atau memperluas yang asli dengan fitur tambahan, tetapi jangan mengubah modul asli.
  • untuk suatu fungsi (yaitu fungsi statis, bukan metode kelas): contoh Anda masuk akal bagi saya; menggunakan kembali fungsi IsAdmin (int) asli di dalam IsAdmin (string) baru. aslinya tidak berubah, fungsi baru memperluas fungsinya.

bidikan di kaki adalah bahwa jika kode Anda menggunakan kelas 'cUserInfo' di mana IsAdmin (int) berada, Anda pada dasarnya melanggar aturan dan mengubah kelas. aturan sayangnya hanya akan disimpan jika Anda membuat kelas baru cUserWithNameInfo: public cUserInfo class dan meletakkan IsAdmin (string) Anda menimpa di sana. Jika saya memiliki basis kode, saya tidak akan pernah mematuhi aturan. Saya akan mengatakan omong kosong dan hanya membuat perubahan yang Anda sarankan.

Sassafras_wot
sumber
3

Pertama, contoh Anda sayangnya dibuat-buat. Anda tidak akan pernah melakukan itu di dunia nyata, karena hal itu menyebabkan mendapatkan dua hal yang tidak perlu. Atau, lebih buruk, karena userid dan nama pengguna mungkin menjadi tipe yang sama di beberapa titik. Daripada

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUser(userid);
    return user.IsAdmin();
}

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

Anda harus benar-benar memperpanjang kelas itu.

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUserById(userid);
    return user.IsAdmin();
}

public bool IsUsernameAdmin(string username)
{
    User userId = UserManager.GetUserByName(username);
    return user.IsAdmin();
}

Anda dapat melanjutkan refactor dan mengubah nama metode pertama menjadi IsUserIdAdmin, untuk konsistensi, tetapi itu tidak perlu. Intinya adalah bahwa, dalam menambahkan metode baru dan menjamin tidak ada kode panggilan yang rusak, Anda telah menemukan kelas Anda bisa diperluas. Atau dengan kata lain, terbuka untuk ekstensi .

Dan ada satu hal dengan prinsip buka-tutup. Anda tidak pernah benar - benar tahu seberapa baik kode Anda sesuai sampai Anda mencoba untuk memperpanjang sebagian darinya dan ternyata Anda harus memodifikasi (dengan meningkatnya risiko yang menyertainya). Tapi, dengan pengalaman, Anda belajar memprediksi.

Seperti kata Paman Bob (penekanan milikku):

Karena penutupan tidak bisa lengkap, itu harus strategis. Artinya, perancang harus memilih jenis perubahan yang akan menutup desainnya. Ini membutuhkan sejumlah prescience yang berasal dari pengalaman . Perancang yang berpengalaman tahu pengguna dan industri dengan cukup baik untuk menilai kemungkinan berbagai jenis perubahan. Dia kemudian memastikan bahwa prinsip buka-tutup dipanggil untuk perubahan yang paling mungkin.

pdr
sumber
Terima kasih atas penjelasan Anda yang baik. Tetapi memiliki 1000 perjalanan pulang pergi atau satu perjalanan pulang pergi bukanlah poin utama di sini. Karena itu mari kita lupakan kinerja saat ini. Namun, apa yang saya lakukan juga untuk memperluas kelas, karena saya telah menambahkan metode lain untuk itu, meskipun dengan nama yang sama, tetapi dengan parameter input yang berbeda. Tapi saya sangat menghargai kutipan Anda dari paman Bob . +1. ;)
Saeed Neamati
@ SaeedNeamati: Poin yang saya buat adalah bahwa tidak masalah jika Anda menambahkan metode yang menggunakan metode yang ada atau menambahkan metode yang sepenuhnya independen, baik cara kelas Anda terbuka untuk ekstensi. Tetapi, jika Anda harus memodifikasi antarmuka metode yang ada untuk mencapai itu, maka Anda tidak tertutup untuk modifikasi.
pdr
2

Modul yang sesuai dengan prinsip buka-tutup memiliki dua atribut utama.

  1. Mereka adalah "Open For Extension". Ini berarti bahwa perilaku modul dapat diperluas. Kita dapat membuat modul berperilaku dengan cara yang baru dan berbeda saat persyaratan aplikasi berubah, atau untuk memenuhi kebutuhan aplikasi baru.
  2. Mereka "Ditutup untuk Modifikasi". Kode sumber modul tersebut tidak dapat diganggu gugat. Tidak ada yang diizinkan untuk melakukan perubahan kode sumber.
  1. Dengan membebani metode Anda, Anda memperluas fungsionalitas modul yang ada, sehingga memenuhi kebutuhan baru aplikasi Anda

  2. Anda tidak melakukan perubahan apa pun pada metode yang ada, jadi Anda tidak melanggar aturan kedua.

Saya akan tertarik untuk mendengar apa yang orang lain katakan tentang tidak memperbolehkan untuk mengubah metode asli. Ya, Anda dapat menempatkan pengubah akses yang sesuai dan memberlakukan enkapsulasi, tetapi apa lagi yang bisa dilakukan?

Ref: http://www.objectmentor.com/resources/articles/ocp.pdf

CodeART
sumber
1

Prinsip Terbuka-Tertutup adalah tujuan, kasus ideal, tidak selalu kenyataan. Khususnya ketika mencari untuk memperbaiki kode lama, langkah pertama sering modifikasi berat untuk membuat OCP kemungkinan. Akar dari prinsipnya adalah bahwa kode kerja sudah berfungsi, dan mengubah kemungkinan memperkenalkan bug. Karenanya skenario terbaik adalah tidak mengubah kode yang ada, hanya menambahkan kode baru.

Tapi katakanlah Anda memiliki fungsi yang dipanggil BigContrivedMethod(int1, int2, string1). BigContrivedMethodmelakukan tiga hal: thing1, thing2, dan thing3. Pada titik ini, menggunakan kembali BCM mungkin sulit, karena terlalu banyak. Refactoring itu (jika mungkin) menjadi ContrivedFunction1(int),, ContrivedFunction2(int)dan ContrivedFunction3(string)memberi Anda tiga metode yang lebih kecil, lebih fokus yang dapat Anda gabungkan dengan lebih mudah.

Dan itulah kunci untuk OCP dalam hal metode / fungsi: komposisi. Anda "memperluas" fungsi dengan memanggilnya dari fungsi lain.

Ingatlah bahwa OCP adalah bagian dari 5 prinsip lainnya, pedoman SOLID. Yang pertama adalah kunci, Tanggung Jawab Tunggal. Jika semua yang ada di basis kode Anda hanya melakukan satu hal spesifik yang harus dilakukan, Anda tidak perlu mengubah kode. Anda hanya perlu menambahkan kode baru atau menggabungkan kode lama dengan cara baru. Karena kode asli jarang memenuhi pedoman itu, Anda sering harus memodifikasinya untuk mendapatkan SRP sebelum Anda bisa mendapatkan OCP.

CodexArcanum
sumber
Saya pikir Anda berbicara tentang Kepala Satu Tanggung Jawab di sini, bukan OCP.
Saeed Neamati
1
Saya mengatakan bahwa Anda tidak dapat secara realistis memiliki OCP tanpa SRP. Kode yang terlalu banyak tidak dapat diperpanjang, tidak dapat digunakan kembali. SOLID hampir ditulis dalam urutan kepentingan, dengan masing-masing prinsip bergantung pada yang sebelum layak.
CodexArcanum
Jawaban ini harus lebih ditingkatkan.
Ashish Gupta
0

Anda mengikuti prinsip terbuka-tertutup jika Anda mengubah perilaku program Anda dengan menulis kode baru daripada mengubah kode lama.

Karena sangat mustahil untuk menulis kode yang terbuka untuk setiap kemungkinan perubahan (dan Anda tidak mau karena Anda memasukkan kelumpuhan analisis), Anda menulis kode yang merespons semua perilaku berbeda yang saat ini Anda kerjakan dengan ekstensi daripada modifikasi.

Ketika Anda mengalami sesuatu yang perlu Anda ubah, alih-alih hanya mengubah sesuatu untuk memungkinkan perilaku baru, Anda mencari tahu apa titik perubahannya, merestrukturisasi program Anda tanpa mengubah perilakunya sehingga Anda kemudian dapat mengubah perilaku itu dengan menulis kode BARU .

Jadi, bagaimana ini berlaku untuk kasus Anda:

Jika Anda menambahkan fungsi baru ke kelas Anda maka kelas Anda tidak terbuka / tertutup tetapi klien dari fungsi yang Anda overloading adalah.

Jika Anda hanya menambahkan fungsi-fungsi baru yang berfungsi DI kelas Anda, maka baik itu dan klien dari fungsi Anda terbuka / tertutup.

Edward Strange
sumber