Apakah Prinsip Tanggung Jawab Tunggal berlaku untuk fungsi?

17

Menurut Robert C. Martin, SRP menyatakan bahwa:

Seharusnya tidak ada lebih dari satu alasan bagi kelas untuk berubah.

Namun, dalam bukunya Clean Code , bab 3: Functions, ia menunjukkan blok kode berikut:

    public Money calculatePay(Employee e) throws InvalidEmployeeType {
        switch (e.type) {
            case COMMISSIONED:
                return calculateCommissionedPay(e);
            case HOURLY:
                return calculateHourlyPay(e);
            case SALARIED:
                return calculateSalariedPay(e);
            default:
                throw new InvalidEmployeeType(e.type);
        }
    }

Dan kemudian nyatakan:

Ada beberapa masalah dengan fungsi ini. Pertama, itu besar, dan ketika tipe karyawan baru ditambahkan, itu akan tumbuh. Kedua, sangat jelas melakukan lebih dari satu hal. Ketiga, itu melanggar Prinsip Tanggung Jawab Tunggal (SRP) karena ada lebih dari satu alasan untuk itu berubah . [penekanan milikku]

Pertama, saya pikir SRP didefinisikan untuk kelas, tetapi ternyata itu juga berlaku untuk fungsi. Kedua, bagaimana fungsi ini memiliki lebih dari satu alasan untuk berubah ? Saya hanya bisa melihatnya berubah karena perubahan pada Karyawan.

Enrique
sumber
5
Ini seperti kasus buku teks untuk polimorfisme.
wchargin
Ini adalah topik yang sangat menarik. Apakah ada kemungkinan Anda menambahkan solusi berikut untuk masalah ini? Saya akan seggust bahwa satu meletakkan perhitungan CalculPay di setiap kelas karyawan tetapi itu akan menjadi buruk karena sekarang setiap kelas karyawan dapat diubah karena: 1. Perhitungan pembayaran. 2. menambahkan lebih banyak properti ke kelas dll.
Stav Alfi

Jawaban:

13

Satu detail yang sering terlewatkan dari Prinsip Tanggung Jawab Tunggal adalah bahwa "alasan untuk perubahan" dikelompokkan oleh aktor-aktor kasus penggunaan (Anda dapat melihat penjelasan lengkap di sini ).

Jadi, dalam contoh Anda, calculatePaymetode ini perlu diubah setiap kali tipe Karyawan baru diperlukan. Karena satu jenis karyawan mungkin tidak ada hubungannya dengan yang lain, itu akan menjadi pelanggaran prinsip jika Anda tetap bersama, karena perubahan akan mempengaruhi kelompok pengguna yang berbeda (atau aktor kasus penggunaan) dalam sistem.

Sekarang, tentang apakah prinsip berlaku untuk fungsi: Bahkan jika Anda memiliki pelanggaran hanya dalam satu metode, Anda masih mengubah kelas karena lebih dari satu alasan, jadi itu masih merupakan pelanggaran SRP.

MichelHenrich
sumber
1
Saya mencoba menonton video youtube yang ditautkan, tetapi setelah 10 menit tanpa menyebutkan pengelompokan oleh aktor use-case, saya menyerah. 6 menit pertama semua bertele-tele tentang entropi, tanpa alasan yang jelas. Jika Anda memberikan lokasi di video di mana ia mulai mendiskusikan hal ini, akan sangat membantu.
Michael Shaw
@MichaelShaw Coba tonton mulai 10:40. Paman Bob menyebutkan bahwa kode akan "berubah karena alasan yang berbeda, karena orang yang berbeda". Saya pikir mungkin itulah yang ingin ditunjukkan oleh MichelHenrich.
Enrique
Selesai menonton seluruh video youtube 50 menit, yang sebagian besar bukan tentang apa yang seharusnya diperjelas. Saya perhatikan pada tanda 16:00 bahwa dia sudah pindah dari topik itu, dan dia tidak pernah kembali ke sana. "Penjelasan" pada dasarnya bermuara pada ini: "tanggung jawab" dalam SRP tidak berarti bahwa, itu berarti "alasan berbeda untuk perubahan", yang benar-benar berarti "perubahan atas permintaan orang yang berbeda", yang benar-benar berarti "perubahan pada permintaan peran berbeda yang dimainkan orang ". "Penjelasan" tidak menjelaskan apa pun, itu menggantikan satu kata yang tidak jelas dengan yang lain.
Michael Shaw
2
@MichaelShaw seperti dalam kutipan dari buku, jika Anda perlu memperkenalkan tipe karyawan yang berbeda, Anda harus mengubah kelas Karyawan. Peran yang berbeda mungkin bertanggung jawab untuk pembayaran jenis karyawan yang berbeda, sehingga dalam kasus ini, kelas Karyawan harus diubah untuk lebih dari satu peran, sehingga melanggar SRP.
MichelHenrich
1
@MichaelShaw ya, Anda benar - SRP bergantung pada bagaimana organisasi diatur. Itulah mengapa saya menambahkan "mungkin" atau "mungkin" ke semua komentar saya :). Namun, bahkan dalam kasus-kasus itu, sementara kode mungkin tidak melanggar SRP, itu pasti melanggar OCP.
MichelHenrich
3

Pada halaman 176, Bab 12: Munculnya, di bagian berjudul Kelas dan Metode Minimal buku ini memberikan sedikit koreksi, dengan menyatakan:

Dalam upaya membuat kelas dan metode kita kecil, kita mungkin membuat terlalu banyak kelas dan metode kecil. Jadi aturan ini menunjukkan bahwa kita juga menjaga fungsi dan kelas kita tetap rendah

dan

Hitungan kelas dan metode yang tinggi kadang-kadang merupakan hasil dari dogmatisme sia-sia.

Jelas, dia berbicara tentang dogmatisme dalam mengikuti SRP untuk memecah metode-metode kecil yang tidak bersalah seperti di calculatePay()atas.

Mike Nakis
sumber
3

Ketika Tn. Martin menerapkan SRP ke suatu fungsi, dia secara implisit memperluas definisi tentang SRP. Karena SRP adalah kata-kata spesifik OO dari prinsip umum, dan karena itu ide yang bagus ketika diterapkan pada fungsi, saya tidak melihat masalah dengan itu (walaupun mungkin lebih baik jika dia secara eksplisit memasukkannya dalam definisi).

Saya juga tidak melihat lebih dari satu alasan untuk berubah, dan saya tidak percaya bahwa memikirkan SRP dalam hal "tanggung jawab" atau "alasan untuk berubah" sangat membantu. Pada dasarnya apa yang didapat SRP adalah bahwa entitas perangkat lunak (fungsi, kelas, dll.) Harus melakukan satu hal dan melakukannya dengan baik.

Jika Anda melihat definisi saya, itu tidak kurang kabur dari kata-kata SRP yang biasa. Masalah dengan definisi biasa dari SRP bukanlah bahwa mereka terlalu kabur, tetapi mereka mencoba untuk terlalu spesifik tentang sesuatu yang pada dasarnya tidak jelas.

Jika Anda melihat apa yang calculatePaydilakukan, itu jelas melakukan satu hal: pengiriman berdasarkan tipe. Karena Java memiliki cara built-in untuk melakukan pengiriman berbasis tipe, calculatePaytidak elok dan non-idiomatis, sehingga harus ditulis ulang, tetapi tidak untuk alasan yang disebutkan.

Michael Shaw
sumber
-2

Anda benar @ Enrique. Tidak masalah apakah itu fungsi atau metode kelas, SRP berarti bahwa dalam blok kode itu Anda hanya melakukan satu hal.

Pernyataan 'alasan untuk mengubah' kadang-kadang agak menyesatkan, tetapi jika Anda mengubah calculateSalariedPayatau calculateHourlyPayatau enum Employee.typeAnda harus mengubah metode ini.

Dalam contoh Anda, fungsinya:

  • memeriksa tipe karyawan
  • memanggil fungsi lain yang menghitung uang sesuai dengan jenisnya

Menurut pendapat saya itu bukan pelanggaran SRP secara langsung, karena sakelar dan panggilan tidak dapat ditulis lebih pendek, jika Anda memikirkan Karyawan dan metode yang sudah ada. Pokoknya itu adalah pelanggaran prinsip terbuka-tertutup (OCP) yang jelas karena Anda harus menambahkan pernyataan 'kasus' jika Anda menambahkan jenis karyawan, jadi ini adalah implementasi yang buruk: refactor it.

Kami tidak tahu bagaimana 'Uang' harus dihitung, tetapi cara termudah adalah dengan memiliki Employeeantarmuka dan beberapa implementasi konkret dengan getMoneymetode. Dalam hal ini seluruh fungsi tidak perlu.

Jika lebih rumit untuk menghitungnya, orang dapat menggunakan pola pengunjung yang juga bukan 100% SRP tetapi lebih banyak OCP daripada switch case.

Aitch
sumber
2
Tidak yakin bagaimana Anda bisa mendaftar 2 hal fungsi, tetapi mengatakan itu bukan pelanggaran SRP.
JeffO
@ Jeffe: Itu bukan 2 hal, itu 2 bagian dari satu hal: memanggil fungsi yang sesuai berdasarkan jenisnya.
Michael Shaw