Pro dan Kontra dari konstanta Antarmuka [closed]

105

Antarmuka PHP memungkinkan definisi konstanta dalam sebuah antarmuka, misalnya

interface FooBar
{
    const FOO = 1;
    const BAR = 2;
}
echo FooBar::FOO; // 1

Setiap kelas pelaksana akan secara otomatis memiliki konstanta ini, misalnya

class MyFooBar implement FooBar
{
}
echo MyFooBar::FOO; // 1

Pendapat saya sendiri adalah bahwa apa pun yang Global itu Jahat . Tetapi saya bertanya-tanya apakah hal yang sama berlaku untuk Konstanta Antarmuka. Mengingat bahwa Coding terhadap Antarmuka dianggap praktik yang baik secara umum, apakah menggunakan Konstanta Antarmuka satu-satunya konstanta yang dapat diterima untuk digunakan di luar konteks kelas?

Meskipun saya ingin tahu pendapat pribadi Anda dan apakah Anda menggunakan konstanta Antarmuka atau tidak, saya terutama mencari alasan obyektif dalam jawaban Anda. Saya tidak ingin ini menjadi pertanyaan Jenis Jajak Pendapat. Saya tertarik pada efek apa yang menggunakan konstanta antarmuka pada Maintainability. Kopel. Atau Pengujian Unit. Bagaimana hubungannya dengan SOLID PHP? Apakah itu melanggar prinsip pengkodean yang dianggap Praktik Baik di PHP? Anda mengerti ...

Catatan: ada pertanyaan serupa untuk Java yang mencantumkan beberapa alasan yang cukup bagus mengapa mereka Praktik Buruk, tetapi karena Java bukan PHP, saya merasa dibenarkan untuk menanyakannya lagi dalam tag PHP.

Gordon
sumber
1
Hmm, saya belum pernah menemukan kebutuhan untuk mendefinisikan konstanta di antarmuka sebelumnya. Perlu diketahui bahwa kelas yang mengimplementasikan antarmuka tidak dapat mengganti konstanta, sementara kelas yang hanya saling memperluas dapat menimpa konstanta.
Charles
1
Saya percaya konstanta tidak buruk karena memiliki nilai yang dapat diprediksi bahkan ketika kita prihatin dengan unit testability. Variabel global adalah jahat karena siapa pun dapat mengubahnya karena itu adalah variabel dan semuanya memiliki ruang lingkup di atasnya tetapi konstanta tidak akan pernah mengubah nilainya sehingga istilahnya konstan.
mdprotacio

Jawaban:

135

Nah, saya berpikir bahwa itu bermuara pada perbedaan antara yang baik dan cukup baik .

Meskipun dalam banyak kasus Anda dapat menghindari penggunaan konstanta dengan menerapkan pola lain (strategi atau mungkin kelas terbang), ada sesuatu yang bisa dikatakan karena tidak memerlukan setengah lusin kelas lain untuk mewakili sebuah konsep. Saya pikir intinya adalah, seberapa besar kemungkinan ada kebutuhan akan konstanta lain. Dengan kata lain, apakah ada kebutuhan untuk memperluas ENUM yang disediakan oleh konstanta pada antarmuka. Jika Anda merasa perlu untuk mengembangkannya, gunakan pola yang lebih formal. Jika tidak, maka itu mungkin cukup (itu akan cukup baik, dan karenanya lebih sedikit kode untuk ditulis dan diuji). Berikut contoh penggunaan yang cukup baik dan buruk:

Buruk:

interface User {
    const TYPE_ADMINISTRATOR = 1;
    const TYPE_USER          = 2;
    const TYPE_GUEST         = 3;
}

Cukup baik:

interface HTTPRequest_1_1 {
    const TYPE_CONNECT = 'connect';
    const TYPE_DELETE  = 'delete';
    const TYPE_GET     = 'get';
    const TYPE_HEAD    = 'head';
    const TYPE_OPTIONS = 'options';
    const TYPE_POST    = 'post';
    const TYPE_PUT     = 'put';

    public function getType();
}

Sekarang, alasan saya memilih contoh tersebut sederhana. The Userinterface mendefinisikan enum jenis pengguna. Ini kemungkinan besar akan berkembang seiring waktu dan akan lebih cocok dengan pola lain. Tetapi HTTPRequest_1_1ini adalah kasus penggunaan yang layak, karena enum ditentukan oleh RFC2616 dan tidak akan berubah selama masa pakai kelas.

Secara umum, saya tidak melihat masalah dengan konstanta dan konstanta kelas sebagai masalah global . Saya melihatnya sebagai masalah ketergantungan. Ini perbedaan yang sempit, tetapi yang pasti. Saya melihat masalah global seperti dalam variabel global yang tidak diberlakukan, dan dengan demikian menciptakan ketergantungan global yang lunak. Tapi kelas hard-code menciptakan ketergantungan yang diberlakukan, dan dengan demikian membuat ketergantungan global yang keras. Jadi keduanya adalah dependensi. Tetapi saya menganggap global menjadi jauh lebih buruk karena tidak diberlakukan ... Itulah sebabnya saya tidak suka menggabungkan dependensi kelas dengan dependensi global di bawah spanduk yang sama ...

Jika Anda menulis MyClass::FOO, Anda akan mendapatkan hardcode untuk detail implementasi MyClass. Ini menciptakan hard-coupling, yang membuat kode Anda kurang fleksibel, dan karenanya harus dihindari. Namun, antarmuka ada untuk mengizinkan jenis kopling ini dengan tepat. Oleh karena MyInterface::FOOitu jangan memperkenalkan kopling beton apa pun. Dengan itu, saya tidak akan memperkenalkan antarmuka hanya untuk menambahkan konstanta padanya.

Jadi jika Anda menggunakan antarmuka, dan Anda sangat yakin bahwa Anda (atau siapa pun dalam hal ini) tidak memerlukan nilai tambahan, maka saya tidak benar-benar melihat masalah besar dengan konstanta antarmuka ... desain tidak akan menyertakan konstanta atau kondisional atau angka ajaib atau string ajaib atau apapun yang di-hardcode. Namun, itu menambah waktu tambahan untuk pengembangan, karena Anda harus mempertimbangkan kegunaannya. Pandangan saya adalah bahwa sering kali sangat berharga untuk meluangkan waktu tambahan untuk membangun desain yang solid dan hebat. Tetapi ada kalanya cukup baik benar-benar dapat diterima (dan dibutuhkan pengembang yang berpengalaman untuk memahami perbedaannya), dan dalam kasus itu tidak masalah.

Sekali lagi, itu hanya pandangan saya tentang itu ...

ircmaxell
sumber
4
Apa yang Anda sarankan sebagai pola berbeda untuk Pengguna dalam kasus ini?
Jacob
@ Jacob: Saya akan mengabstraksikannya. Bergantung pada kebutuhan Anda, saya mungkin akan membuat kelas Access yang akan mendapatkan datanya dari tabel database. Dengan cara itu menambahkan level baru semudah memasukkan baris baru. Opsi lainnya adalah membuat kumpulan kelas ENUM (di mana Anda memiliki satu kelas untuk setiap peran izin). Kemudian Anda dapat memperluas kelas jika perlu untuk memberikan izin yang sesuai. Tetapi ada metode lain yang juga akan berhasil
ircmaxell
3
Jawaban yang sangat solid dan diartikulasikan dengan baik! +1
Decent Dabbler
1
kelas dengan konstanta publik seharusnya tidak memiliki metode apa pun. Seharusnya hanya struktur data atau objek saja - tidak keduanya.
OZ_
2
@FrederikKrautwald: Anda dapat menghindari kondisional dengan polimorfisme (dalam banyak kasus): Periksa jawaban ini serta tonton pembicaraan Kode Bersih ini ...
ircmaxell
10

Menurut saya, biasanya lebih baik menangani konstanta, konstanta yang disebutkan secara khusus, sebagai tipe terpisah ("class") dari antarmuka Anda:

define(TYPE_CONNECT, 'connect');
define(TYPE_DELETE , 'delete');
define(TYPE_GET    , 'get');
define(TYPE_HEAD   , 'head');
define(TYPE_OPTIONS, 'options');
define(TYPE_POST   , 'post');
define(TYPE_PUT    , 'put');

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

atau, jika Anda ingin menggunakan kelas sebagai namespace:

class TypeHTTP_Enums
{
  const TYPE_CONNECT = 'connect';
  const TYPE_DELETE  = 'delete';
  const TYPE_GET     = 'get';
  const TYPE_HEAD    = 'head';
  const TYPE_OPTIONS = 'options';
  const TYPE_POST    = 'post';
  const TYPE_PUT     = 'put';
}

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

Ini bukan berarti Anda hanya menggunakan konstanta, Anda menggunakan konsep enumerasi nilai atau enumerasi, yang sekumpulan nilai terbatas, dianggap sebagai jenis tertentu, dengan penggunaan tertentu ("domain"?)

umlcat
sumber