CodeGym /Blog Java /rawak /Apakah anti-corak? Mari lihat beberapa contoh (Bahagian 2...
John Squirrels
Tahap
San Francisco

Apakah anti-corak? Mari lihat beberapa contoh (Bahagian 2)

Diterbitkan dalam kumpulan
Apakah anti-corak? Mari lihat beberapa contoh (Bahagian 1) Hari ini kami meneruskan ulasan kami tentang anti-corak yang paling popular. Jika anda terlepas bahagian pertama, ini dia. Apakah anti-corak?  Mari lihat beberapa contoh (Bahagian 2) - 1Jadi, corak reka bentuk adalah amalan terbaik. Dalam erti kata lain, mereka adalah contoh cara yang baik dan teruji masa untuk menyelesaikan masalah tertentu. Sebaliknya, anti-corak adalah bertentangan dengannya, dalam erti kata bahawa ia adalah corak perangkap atau kesilapan ketika menyelesaikan pelbagai masalah (pola jahat). Mari kita teruskan ke anti-corak pembangunan perisian seterusnya.

8. Tukul emas

Tukul emas ialah anti-corak yang ditakrifkan dengan keyakinan bahawa penyelesaian tertentu boleh digunakan secara universal. Contoh:
  1. Selepas menghadapi masalah dan mencari corak untuk penyelesaian yang sempurna, seorang pengaturcara cuba melekatkan corak ini di mana-mana, menerapkannya pada projek semasa dan semua projek masa depan, dan bukannya mencari penyelesaian yang sesuai untuk kes tertentu.

  2. Sesetengah pembangun pernah mencipta varian cache mereka sendiri untuk situasi tertentu (kerana tiada perkara lain yang sesuai). Kemudian, pada projek seterusnya yang tidak melibatkan logik cache khas, mereka menggunakan varian mereka sekali lagi dan bukannya menggunakan perpustakaan siap pakai (contohnya, Ehcache). Hasilnya ialah sekumpulan pepijat dan ketidakserasian, serta banyak masa yang terbuang dan saraf goreng.

    Sesiapa sahaja boleh jatuh cinta dengan anti-corak ini. Jika anda seorang pemula, anda mungkin tidak arif tentang corak reka bentuk. Ini boleh membawa anda untuk cuba menyelesaikan semua masalah dalam satu cara yang telah anda kuasai. Jika kita bercakap tentang profesional, maka kita panggil ini ubah bentuk profesional atau nerdview. Anda mempunyai corak reka bentuk pilihan anda sendiri, dan bukannya menggunakan yang betul, anda menggunakan kegemaran anda, dengan mengandaikan bahawa kesesuaian yang baik pada masa lalu menjamin hasil yang sama pada masa hadapan.

    Perangkap ini boleh menghasilkan keputusan yang sangat menyedihkan — daripada pelaksanaan yang buruk, tidak stabil dan sukar dikekalkan kepada kegagalan sepenuhnya projek. Sama seperti tiada satu pil untuk semua penyakit, tiada satu corak reka bentuk untuk semua keadaan.

9. Pengoptimuman pramatang

Pengoptimuman pramatang ialah anti-corak yang namanya bercakap untuk dirinya sendiri.
"Pengaturcara menghabiskan banyak masa untuk berfikir dan bimbang tentang tempat yang tidak kritikal dalam kod dan cuba mengoptimumkannya, yang hanya memberi kesan negatif pada penyahpepijatan dan sokongan berikutnya. Secara amnya, kita harus melupakan pengoptimuman dalam, katakan, 97% kes. Lebih-lebih lagi , pengoptimuman pramatang adalah punca kepada semua kejahatan. Oleh itu, kita mesti memberi perhatian kepada baki 3% lagi." - Donald Knuth
Contohnya, menambahkan indeks pada pangkalan data secara pramatang. Kenapa teruk? Nah, ia adalah buruk dalam hal itu, indeks disimpan sebagai pokok binari. Akibatnya, setiap kali nilai baharu ditambah dan dipadamkan, pokok itu akan dikira semula, dan ini menggunakan sumber dan masa. Oleh itu, indeks harus ditambah hanya apabila terdapat keperluan mendesak (jika anda mempunyai jumlah data yang besar dan pertanyaan mengambil masa terlalu lama) dan hanya untuk medan yang paling penting (medan yang paling kerap ditanya).

10. Kod spageti

Kod spageti ialah anti-corak yang ditakrifkan oleh kod yang tidak berstruktur, mengelirukan dan sukar difahami, mengandungi semua jenis percabangan, seperti pengecualian pembalut, syarat dan gelung. Sebelum ini, pengendali goto adalah sekutu utama anti-corak ini. Kenyataan Goto tidak digunakan lagi, yang dengan senang hati menghapuskan beberapa kesukaran dan masalah yang berkaitan.

public boolean someDifficultMethod(List<String> XMLAttrList) {
           ...
   int prefix = stringPool.getPrefixForQName(elementType);
   int elementURI;
   try {
       if (prefix == -1) {
        ...
           if (elementURI != -1) {
               stringPool.setURIForQName(...);
           }
       } else {
        ...
           if (elementURI == -1) {
           ...
           }
       }
   } catch (Exception e) {
       return false;
   }
   if (attrIndex != -1) {
       int index = attrList.getFirstAttr(attrIndex);
       while (index != -1) {
           int attName = attrList.getAttrName(index);
           if (!stringPool.equalNames(...)){
           ...
               if (attPrefix != namespacesPrefix) {
                   if (attPrefix == -1) {
                    ...
                   } else {
                       if (uri == -1) {
                       ...
                       }
                       stringPool.setURIForQName(attName, uri);
                   ...
                   }
                   if (elementDepth >= 0) {
                   ...
                   }
                   elementDepth++;
                   if (elementDepth == fElementTypeStack.length) {
                   ...
                   }
               ...
                   return contentSpecType == fCHILDRENSymbol;
               }
           }
       }
   }
}
Ia kelihatan mengerikan, bukan? Malangnya, ini adalah anti-corak yang paling biasa :( Malah orang yang menulis kod sedemikian tidak akan dapat memahaminya pada masa hadapan. Pembangun lain yang melihat kod itu akan berfikir, "Nah, jika ia berfungsi, maka okey — adalah lebih baik untuk tidak menyentuhnya". Selalunya, kaedah pada mulanya mudah dan sangat telus, tetapi apabila keperluan baru ditambah, kaedah itu secara beransur-ansur dibebani dengan lebih banyak kenyataan bersyarat, mengubahnya menjadi raksasa seperti ini. Jika kaedah sedemikian muncul, anda perlu memfaktorkannya semula sama ada sepenuhnya atau sekurang-kurangnya bahagian yang paling mengelirukan. Biasanya, apabila menjadualkan projek, masa diperuntukkan untuk pemfaktoran semula, contohnya, 30% daripada masa pecut adalah untuk pemfaktoran semula dan ujian. Sudah tentu, ini mengandaikan bahawa tidak ada sebarang tergesa-gesa (tetapi bilakah perkara itu berlaku).di sini .

11. Nombor ajaib

Nombor ajaib ialah anti-corak di mana semua jenis pemalar digunakan dalam program tanpa sebarang penjelasan tentang tujuan atau maknanya. Iaitu, mereka secara amnya tidak dinamakan atau dalam kes yang melampau, tidak ada ulasan yang menjelaskan apa komen itu atau mengapa. Seperti kod spageti, ini adalah salah satu anti-corak yang paling biasa. Seseorang yang tidak menulis kod mungkin atau mungkin tidak mempunyai petunjuk tentang nombor ajaib atau cara ia berfungsi (dan pada masanya, pengarang sendiri tidak akan dapat menjelaskannya). Akibatnya, menukar atau mengalih keluar nombor menyebabkan kod secara ajaib berhenti berfungsi bersama-sama. Sebagai contoh, 36 dan 73. Untuk memerangi anti-corak ini, saya mengesyorkan semakan kod. Kod anda perlu dilihat oleh pembangun yang tidak terlibat dalam bahagian kod yang berkaitan. Mata mereka akan segar dan mereka akan mempunyai soalan: apakah ini dan mengapa anda berbuat demikian? Dan sudah tentu, anda perlu menggunakan nama penjelasan atau meninggalkan komen.

12. Salin dan tampal pengaturcaraan

Pengaturcaraan salin dan tampal ialah anti-corak di mana kod orang lain disalin dan ditampal tanpa fikir, mungkin mengakibatkan kesan sampingan yang tidak dijangka. Contohnya, menyalin dan menampal kaedah dengan pengiraan matematik atau algoritma kompleks yang kita tidak faham sepenuhnya. Ia mungkin berfungsi untuk kes tertentu kami, tetapi dalam beberapa keadaan lain ia boleh membawa kepada masalah. Katakan saya memerlukan kaedah untuk menentukan nombor maksimum dalam tatasusunan. Membelek-belek Internet, saya dapati penyelesaian ini:

public static int max(int[] array) {
   int max = 0;
   for(int i = 0; i < array.length; i++) {
       if (Math.abs(array[i]) > max){
           max = array[i];
       }
   }
   return max;
}
Kami mendapat tatasusunan dengan nombor 3, 6, 1, 4, dan 2, dan kaedah itu mengembalikan 6. Bagus, mari kekalkan! Tetapi kemudian kita mendapat tatasusunan yang terdiri daripada 2.5, -7, 2, dan 3, dan kemudian keputusan kita ialah -7. Dan keputusan ini tidak baik. Masalahnya di sini ialah Math.abs() mengembalikan nilai mutlak. Kejahilan ini membawa kepada bencana, tetapi hanya dalam situasi tertentu. Tanpa pemahaman yang mendalam tentang penyelesaian, terdapat banyak kes yang anda tidak akan dapat mengesahkan. Kod yang disalin juga mungkin melangkaui struktur dalaman aplikasi, dari segi gaya dan pada tahap seni bina yang lebih asas. Kod sedemikian akan menjadi lebih sukar untuk dibaca dan diselenggara. Dan sudah tentu, kita tidak boleh lupa bahawa menyalin terus kod orang lain adalah sejenis plagiarisme yang istimewa.

13. Mencipta semula roda

Mencipta semula roda ialah anti-corak, juga kadangkala dikenali sebagai mencipta semula roda segi empat sama. Pada dasarnya, templat ini adalah bertentangan dengan salin dan tampal anti-corak yang dipertimbangkan di atas. Dalam anti-corak ini, pembangun melaksanakan penyelesaiannya sendiri untuk masalah yang penyelesaiannya sudah wujud. Kadangkala penyelesaian sedia ada ini lebih baik daripada apa yang dicipta oleh pengaturcara. Selalunya, ini hanya membawa kepada kehilangan masa dan produktiviti yang lebih rendah: pengaturcara mungkin tidak menemui penyelesaian sama sekali atau mungkin mencari penyelesaian yang jauh dari yang terbaik. Walau bagaimanapun, kita tidak boleh menolak kemungkinan untuk mencipta penyelesaian bebas, kerana melakukan itu adalah jalan langsung untuk menyalin dan menampal pengaturcaraan. Pengaturcara harus dipandu oleh tugas pengaturcaraan khusus yang timbul untuk menyelesaikannya dengan cekap, sama ada dengan menggunakan penyelesaian siap sedia atau dengan mencipta penyelesaian tersuai. Sangat kerap, sebab menggunakan anti-corak ini adalah tergesa-gesa. Hasilnya ialah analisis cetek (mencari) penyelesaian sedia. Mencipta semula roda empat segi ialah kes di mana anti-corak yang sedang dipertimbangkan mempunyai hasil negatif. Iaitu, projek itu memerlukan penyelesaian tersuai, dan pembangun menciptanya, tetapi teruk. Pada masa yang sama, pilihan yang baik sudah wujud dan orang lain menggunakannya dengan jayanya. Intinya: sejumlah besar masa hilang. Pertama, kami mencipta sesuatu yang tidak berfungsi. Kemudian kami cuba memfaktorkannya semula, dan akhirnya kami menggantikannya dengan sesuatu yang telah wujud. Contohnya ialah melaksanakan cache tersuai anda sendiri apabila banyak pelaksanaan sudah wujud. Tidak kira betapa berbakatnya anda sebagai seorang pengaturcara, anda harus ingat bahawa mencipta semula roda persegi sekurang-kurangnya membuang masa. Dan, seperti yang anda tahu, masa adalah sumber yang paling berharga.

14. Masalah Yo-yo

Masalah yo-yo ialah anti-corak yang struktur aplikasinya terlalu rumit disebabkan oleh pemecahan yang berlebihan (contohnya, rantaian warisan yang dipecah bahagi secara berlebihan). "Masalah yo-yo" timbul apabila anda perlu memahami program yang hierarki warisannya panjang dan rumit, mewujudkan panggilan kaedah bersarang dalam. Akibatnya, pengaturcara perlu menavigasi antara banyak kelas dan kaedah yang berbeza untuk memeriksa tingkah laku program. Nama anti-corak ini berasal dari nama mainan. Sebagai contoh, mari kita lihat rantaian warisan berikut: Kami mempunyai antara muka Teknologi:

public interface Technology {
   void turnOn();
}
Antara muka Pengangkutan mewarisinya:

public interface Transport extends Technology {
   boolean fillUp();
}
Dan kemudian kami mempunyai antara muka lain, GroundTransport:

public interface GroundTransportation extends Transport {
   void startMove();
   void brake();
}
Dan dari sana, kami memperoleh kelas Kereta abstrak:

public abstract class Car implements GroundTransportation {
   @Override
   public boolean fillUp() {
       /* some implementation */
       return true;
   }
   @Override
   public void turnOn() {
       /* some implementation */
   }
   public boolean openTheDoor() {
       /* some implementation */
       return true;
   }
   public abstract void fixCar();
}
Seterusnya ialah kelas Volkswagen abstrak:

public abstract class Volkswagen extends Car {
   @Override
   public void startMove() {
       /* some implementation */
   }
   @Override
   public void brake() {
       /* some implementation */
   }
}
Dan akhirnya, model tertentu:

public class VolkswagenAmarok extends Volkswagen {
   @Override
   public void fixCar(){
       /* some implementation */
   }
}
Rantaian ini memaksa kami untuk mencari jawapan kepada soalan seperti:
  1. Berapa banyak kaedah yang VolkswagenAmarokada?

  2. Apakah jenis yang harus disisipkan dan bukannya tanda soal untuk mencapai abstraksi maksimum:

    
    ? someObj = new VolkswagenAmarok();
           someObj.brake();
    
Sukar untuk menjawab soalan sedemikian dengan cepat — ia memerlukan kita untuk melihat dan menyiasat, dan mudah untuk keliru. Dan bagaimana pula jika hierarkinya jauh lebih besar, lebih panjang dan lebih rumit, dengan pelbagai jenis lebihan dan penggantian? Struktur yang kita ada akan dikaburkan kerana pemecahan yang berlebihan. Penyelesaian terbaik ialah mengurangkan pembahagian yang tidak perlu. Dalam kes kami, kami akan meninggalkan Teknologi → Kereta → VolkswagenAmarok.

15. Kerumitan yang tidak disengajakan

Kerumitan yang tidak perlu ialah anti-corak di mana komplikasi yang tidak perlu diperkenalkan kepada penyelesaian.
"Mana-mana orang bodoh boleh menulis kod yang boleh difahami oleh komputer. Pengaturcara yang baik menulis kod yang boleh difahami oleh manusia." - Martin Fowler
Jadi apakah kerumitan? Ia boleh ditakrifkan sebagai tahap kesukaran setiap operasi dilakukan dalam program. Sebagai peraturan, kerumitan boleh dibahagikan kepada dua jenis. Jenis kerumitan pertama ialah bilangan fungsi yang ada pada sistem. Ia boleh dikurangkan dalam satu cara sahaja — dengan mengalih keluar beberapa fungsi. Kaedah sedia ada perlu dipantau. Sesuatu kaedah harus dialih keluar jika ia tidak lagi digunakan atau masih digunakan tetapi tanpa membawa sebarang nilai. Lebih-lebih lagi, anda perlu menilai cara semua kaedah dalam aplikasi digunakan, untuk memahami di mana pelaburan akan berbaloi (banyak penggunaan semula kod) dan perkara yang anda boleh katakan tidak. Jenis kerumitan kedua ialah kerumitan yang tidak perlu. Ia boleh disembuhkan hanya melalui pendekatan profesional. Daripada melakukan sesuatu yang "sejuk" (pemaju muda bukan satu-satunya yang terdedah kepada penyakit ini), anda perlu memikirkan cara melakukannya semudah mungkin, kerana penyelesaian terbaik sentiasa mudah. Sebagai contoh, katakan kita mempunyai jadual kecil berkaitan dengan perihalan beberapa entiti, seperti pengguna: Apakah anti-corak?  Mari lihat beberapa contoh (Bahagian 2) - 3Jadi, kami mempunyai id pengguna, id bahasa yang digunakan untuk membuat perihalan dan perihalan itu sendiri. Begitu juga, kami mempunyai deskriptor tambahan untuk kereta, fail, pelan dan jadual pelanggan. Kemudian bagaimanakah rupanya untuk memasukkan nilai baharu ke dalam jadual sedemikian?

public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
   switch (type){
       case CAR:
           jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
       case USER:
           jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
       case FILE:
           jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
       case PLAN:
           jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
       case CUSTOMER:
           jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
       default:
           throw new Exception();
   }
}
Dan dengan itu, kami mempunyai enum ini:

public enum ServiceType {
   CAR(),
   USER(),
   FILE(),
   PLAN(),
   CUSTOMER()
}
Segala-galanya nampak mudah dan bagus... Tetapi bagaimana dengan kaedah lain? Malah, mereka juga akan mempunyai sekumpulan switchpernyataan dan sekumpulan pertanyaan pangkalan data yang hampir sama, yang seterusnya akan merumitkan dan membebankan kelas kami. Bagaimana semua ini boleh dipermudahkan? Mari kita tingkatkan sedikit enum kita:

@Getter
@AllArgsConstructor
public enum ServiceType {
   CAR("cars_descriptions", "car_id"),
   USER("users_descriptions", "user_id"),
   FILE("files_descriptions", "file_id"),
   PLAN("plans_descriptions", "plan_id"),
   CUSTOMER("customers_descriptions", "customer_id");
   private String tableName;
   private String columnName;
}
Kini setiap jenis mempunyai nama medan asal jadualnya. Akibatnya, kaedah untuk membuat penerangan menjadi:

private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
   jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
   }
Mudah, ringkas dan padat, bukankah anda fikir? Petunjuk pembangun yang baik bukanlah seberapa kerap dia menggunakan corak, tetapi seberapa kerap dia mengelakkan anti-corak. Kejahilan adalah musuh yang paling teruk, kerana anda perlu mengenali musuh anda dengan penglihatan. Nah, itu sahaja yang saya ada untuk hari ini. Terima kasih semua! :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION