JavaRush /Java Blogu /Random-AZ /Java-da refaktorinq necə işləyir

Java-da refaktorinq necə işləyir

Qrupda dərc edilmişdir
Proqramlaşdırmağı öyrənərkən kod yazmağa çox vaxt sərf olunur. Əksər başlanğıc tərtibatçılar bunun onların gələcək fəaliyyəti olduğuna inanırlar. Bu qismən doğrudur, lakin proqramçının vəzifələrinə kodun saxlanması və refaktorinqi də daxildir. Bu gün biz refaktorinq haqqında danışacağıq. Java-da refaktorinq necə işləyir - 1

JavaRush kursunda refaktorinq

JavaRush kursu iki dəfə refaktorinq mövzusunu əhatə edir: Böyük tapşırıq sayəsində real refaktorinqlə praktikada tanış olmaq imkanı yaranır və IDEA-da refaktorinq üzrə mühazirə həyatı inanılmaz dərəcədə asanlaşdıran avtomatik alətləri anlamağa kömək edəcək.

Refaktorinq nədir?

Bu, kodun funksionallığını dəyişdirmədən strukturunda dəyişiklikdir. Məsələn, 2 ədədi müqayisə edən və birincisi böyük olarsa doğru , əks halda isə yalan qaytaran bir üsul var :
public boolean max(int a, int b) {
    if(a > b) {
        return true;
    } else if(a == b) {
        return false;
    } else {
        return false;
    }
}
Nəticə çox çətin kod oldu. Hətta yeni başlayanlar belə nadir hallarda belə bir şey yazırlar, lakin belə bir risk var. Deyəsən, if-else6 sətir daha qısa bir metod yaza bilsəniz, niyə burada blok var:
public boolean max(int a, int b) {
     return a>b;
}
İndi bu üsul sadə və zərif görünür, baxmayaraq ki, yuxarıdakı nümunə ilə eyni şeyi edir. Refaktorinq belə işləyir: kodun strukturunu onun mahiyyətinə təsir etmədən dəyişir. Daha ətraflı nəzərdən keçirəcəyimiz bir çox refaktorinq üsulları və texnikaları var.

Refaktorinq niyə lazımdır?

Bunun bir neçə səbəbi var. Məsələn, kodun sadəliyinə və yığcamlığına can atmaq. Bu nəzəriyyənin tərəfdarları hesab edirlər ki, kodu anlamaq üçün bir neçə onlarla sətir şərh tələb olunsa belə, mümkün qədər qısa olmalıdır. Digər tərtibatçılar hesab edirlər ki, kodun minimum sayda şərhlərlə başa düşülməsi üçün refaktorasiya edilməlidir. Hər komanda öz mövqeyini seçir, lakin yadda saxlamalıyıq ki, refaktorinq ixtisar deyil . Onun əsas məqsədi kodun strukturunu təkmilləşdirməkdir. Bu qlobal məqsədə bir neçə məqsəd daxil edilə bilər:
  1. Refaktorinq başqa tərtibatçı tərəfindən yazılmış kodun başa düşülməsini yaxşılaşdırır;
  2. Səhvləri tapmağa və düzəltməyə kömək edir;
  3. Proqram təminatının işlənməsi sürətini artırmağa imkan verir;
  4. Ümumilikdə proqram tərkibini yaxşılaşdırır.
Refaktorinq uzun müddət həyata keçirilməzsə, işin tam dayandırılmasına qədər inkişafda çətinliklər yarana bilər.

“Kod iyi gəlir”

Kod refaktorinq tələb etdikdə onlar "qoxu gəlir" deyirlər. Əlbəttə ki, sözün əsl mənasında deyil, amma belə kod həqiqətən çox gözəl görünmür. Aşağıda ilkin mərhələ üçün əsas refaktorinq üsullarını nəzərdən keçirəcəyik.

Lazımsız böyük elementlər

Böyük ölçülərinə görə effektiv şəkildə işləmək mümkün olmayan çətin siniflər və üsullar var.

Böyük sinif

Belə bir sinifdə çoxlu sayda kod sətirləri və çoxlu müxtəlif üsullar var. Bir tərtibatçı üçün yenisini yaratmaqdansa, mövcud sinifə bir xüsusiyyət əlavə etmək daha asandır, buna görə də böyüyür. Bir qayda olaraq, bu sinifin funksionallığı həddindən artıq yüklənir. Bu halda, funksionallığın bir hissəsini ayrıca bir sinifə ayırmaq kömək edir. Bu barədə daha ətraflı refaktorinq texnikaları bölməsində danışacağıq.

Böyük Metod

Bu “qoxu” bir tərtibatçı metoda yeni funksionallıq əlavə etdikdə baş verir. “Bura yaza bilsəm, parametr yoxlamasını niyə ayrıca metoda qoymalıyam?”, “Niyə massivdə maksimum elementi tapmaq üçün metodu ayırmaq lazımdır, onu burada buraxaq. Bu şəkildə kod daha aydın olur” və digər yanlış təsəvvürlər. Böyük bir metodun yenidən qurulması üçün iki qayda var:
  1. Metod yazarkən koda şərh əlavə etmək istəyirsinizsə, bu funksionallığı ayrıca metoda ayırmalısınız;
  2. Metod 10-15 sətirdən çox kod alırsa, onun yerinə yetirdiyi tapşırıqları və alt tapşırıqları müəyyən etməli və alt tapşırıqları ayrıca metoda ayırmağa çalışmalısınız.
Böyük bir üsulu aradan qaldırmağın bir neçə yolu:
  • Metodun funksionallığının bir hissəsini ayrıca metoda ayırın;
  • Əgər yerli dəyişənlər funksionallığın bir hissəsini çıxarmağa imkan vermirsə, siz bütün obyekti başqa metoda ötürə bilərsiniz.

Bir çox primitiv məlumat növlərindən istifadə

Tipik olaraq, bu problem sinifdə məlumatların saxlanması üçün sahələrin sayı zamanla artdıqda baş verir. Məsələn, verilənləri (valyuta, tarix, telefon nömrələri və s.) saxlamaq üçün kiçik obyektlər əvəzinə primitiv tiplərdən və ya hər hansı məlumatı kodlaşdırmaq üçün sabitlərdən istifadə edirsinizsə. Bu vəziyyətdə yaxşı bir təcrübə sahələri məntiqi olaraq qruplaşdırmaq və onları ayrıca bir sinifdə yerləşdirmək olardı (sinif seçərək). Siz həmçinin bu məlumatların işlənməsi üsullarını sinfə daxil edə bilərsiniz.

Seçimlərin uzun siyahısı

Kifayət qədər ümumi bir səhv, xüsusən də böyük bir üsulla birlikdə. Bu, adətən metodun funksionallığı həddən artıq yükləndikdə və ya metod bir neçə alqoritmi birləşdirdikdə baş verir. Parametrlərin uzun siyahılarını başa düşmək çox çətindir və belə üsullardan istifadə etmək əlverişsizdir. Buna görə də, bütün obyekti köçürmək daha yaxşıdır. Obyektdə kifayət qədər məlumat yoxdursa, daha ümumi bir obyektdən istifadə etməyə və ya metodun funksionallığını məntiqi əlaqəli məlumatları emal etməsi üçün bölməyə dəyər.

Məlumat qrupları

Məntiqi əlaqəli məlumat qrupları çox vaxt kodda görünür. Məsələn, verilənlər bazasına qoşulma parametrləri (URL, istifadəçi adı, parol, sxem adı və s.). Elementlər siyahısından heç bir sahə çıxarıla bilmirsə, siyahı ayrıca bir sinifə (sinif seçimi) yerləşdirilməli olan məlumat qrupudur.

OOP konsepsiyasını pozan həllər

Bu tip "qoxu" tərtibatçı OOP dizaynını pozduqda baş verir. Bu, o zaman baş verir ki, o, bu paradiqmanın imkanlarını tam dərk etmir, onlardan natamam və ya səhv istifadə edir.

Vərəsəlikdən imtina

Əgər alt sinif ana sinifin funksiyalarının minimal hissəsindən istifadə edirsə, o, səhv iyerarxiya kimi iyi gəlir. Tipik olaraq, bu halda, lazımsız üsullar sadəcə olaraq ləğv edilmir və ya istisnalar atılır. Bir sinif digərindən miras alınarsa, bu, onun funksionallığından demək olar ki, tam istifadəni nəzərdə tutur. Düzgün iyerarxiya nümunəsi: Java-da refaktorinq necə işləyir - 2 Yanlış iyerarxiya nümunəsi: Java-da refaktorinq necə işləyir - 3

keçid bəyanatı

Operatorda nə səhv ola bilər switch? Dizaynı çox mürəkkəb olduqda pisdir. Bura həm də bir çox yuvalanmış bloklar daxildir if.

Fərqli interfeyslərə malik alternativ siniflər

Bir neçə sinif əslində eyni şeyi edir, lakin onların metodları fərqli adlandırılır.

Müvəqqəti sahə

Sinifdə obyektin yalnız arabir ehtiyac duyduğu müvəqqəti sahə varsa, o, dəyərlərlə doldurulursa və qalan vaxt boşdursa və ya Allah eləməsin, o nullzaman kod "iylənir" və belə bir dizayn şübhəlidir. qərar.

Modifikasiyanı çətinləşdirən qoxular

Bu “qoxular” daha ciddidir. Qalanları əsasən kodun başa düşülməsinə mane olur, halbuki bunlar onu dəyişdirməyə imkan vermir. Hər hansı bir funksiyanı təqdim edərkən, tərtibatçıların yarısı çıxacaq, yarısı isə dəli olacaq.

Paralel miras iyerarxiyaları

Bir sinfin alt sinifini yaratdığınız zaman başqa sinif üçün başqa alt sinif yaratmalısınız.

Asılılığın vahid paylanması

Hər hansı bir modifikasiya edərkən bu sinfin bütün asılılıqlarını (istifadələrini) axtarmaq və bir çox kiçik dəyişikliklər etmək lazımdır. Bir dəyişiklik - bir çox siniflərdə düzəlişlər.

Kompleks modifikasiya ağacı

Bu qoxu əvvəlkinin əksinədir: dəyişikliklər eyni sinifin çox sayda metoduna təsir göstərir. Bir qayda olaraq, bu cür kodda asılılıq kaskaddır: bir metodu dəyişdirərək, başqa birində bir şey düzəltməlisiniz, sonra üçüncüdə və s. Bir sinif - çoxlu dəyişikliklər.

“Zibil iyi gəlir”

Baş ağrısına səbəb olan olduqca xoşagəlməz qoxular kateqoriyası. Yararsız, lazımsız, köhnə kod. Xoşbəxtlikdən, müasir IDE və linterlər bu cür qoxular barədə xəbərdarlıq etməyi öyrəndilər.

Metodda çox sayda şərh

Metodda demək olar ki, hər sətirdə çoxlu izahlı şərhlər var. Bu adətən mürəkkəb alqoritmlə əlaqələndirilir, ona görə də kodu bir neçə kiçik metoda bölmək və onlara mənalı adlar vermək daha yaxşıdır.

Kodun dublikasiyası

Fərqli siniflər və ya metodlar eyni kod bloklarından istifadə edir.

Tənbəl sinif

Sinif çox az funksionallıq götürür, baxmayaraq ki, çoxu planlaşdırılıb.

İstifadə olunmamış kod

Sinif, metod və ya dəyişən kodda istifadə edilmir və “ölü çəki”dir.

Həddindən artıq birləşmə

Bu qoxular kateqoriyası kodda çoxlu sayda lazımsız əlaqə ilə xarakterizə olunur.

Üçüncü tərəf üsulları

Metod başqa obyektin məlumatından öz məlumatından daha tez-tez istifadə edir.

Uyğun olmayan yaxınlıq

Bir sinif digər sinfin xidmət sahələrindən və metodlarından istifadə edir.

Uzun sinif zəngləri

Bir sinif digərini çağırır, o, üçüncüdən, dördüncüdən və s. məlumatları tələb edir. Belə uzun zənglər silsiləsi mövcud sinif strukturundan yüksək səviyyədə asılılıq deməkdir.

Sinif-tapşırıq-diler

Sinif yalnız tapşırığı başqa sinfə ötürmək üçün lazımdır. Bəlkə onu çıxarmaq lazımdır?

Refaktorinq Texnikaları

Aşağıda təsvir olunan kod qoxularını aradan qaldırmağa kömək edəcək ilkin refaktorinq üsulları haqqında danışacağıq.

Sinif seçimi

Sinif həddən artıq çox funksiya yerinə yetirir, onlardan bəzilərini başqa sinfə köçürmək lazımdır. Məsələn, Humanyaşayış ünvanı və tam ünvanı təmin edən metodu ehtiva edən bir sinif var:
class Human {
   private String name;
   private String age;
   private String country;
   private String city;
   private String street;
   private String house;
   private String quarter;

   public String getFullAddress() {
       StringBuilder result = new StringBuilder();
       return result
                       .append(country)
                       .append(", ")
                       .append(city)
                       .append(", ")
                       .append(street)
                       .append(", ")
                       .append(house)
                       .append(" ")
                       .append(quarter).toString();
   }
}
Ünvan məlumatını və metodunu (məlumatların emalı davranışı) ayrıca bir sinifdə yerləşdirmək yaxşı olardı:
class Human {
   private String name;
   private String age;
   private Address address;

   private String getFullAddress() {
       return address.getFullAddress();
   }
}
class Address {
   private String country;
   private String city;
   private String street;
   private String house;
   private String quarter;

   public String getFullAddress() {
       StringBuilder result = new StringBuilder();
       return result
                       .append(country)
                       .append(", ")
                       .append(city)
                       .append(", ")
                       .append(street)
                       .append(", ")
                       .append(house)
                       .append(" ")
                       .append(quarter).toString();
   }
}

Metod seçimi

Metoddakı hər hansı funksionallıq qruplaşdırıla bilirsə, o, ayrıca metodda yerləşdirilməlidir. Məsələn, kvadrat tənliyin köklərini hesablayan bir üsul:
public void calcQuadraticEq(double a, double b, double c) {
    double D = b * b - 4 * a * c;
    if (D > 0) {
        double x1, x2;
        x1 = (-b - Math.sqrt(D)) / (2 * a);
        x2 = (-b + Math.sqrt(D)) / (2 * a);
        System.out.println("x1 = " + x1 + ", x2 = " + x2);
    }
    else if (D == 0) {
        double x;
        x = -b / (2 * a);
        System.out.println("x = " + x);
    }
    else {
        System.out.println("Equation has no roots");
    }
}
Gəlin hər üç mümkün variantın hesablanmasını ayrı-ayrı üsullara keçirək:
public void calcQuadraticEq(double a, double b, double c) {
    double D = b * b - 4 * a * c;
    if (D > 0) {
        dGreaterThanZero(a, b, D);
    }
    else if (D == 0) {
        dEqualsZero(a, b);
    }
    else {
        dLessThanZero();
    }
}

public void dGreaterThanZero(double a, double b, double D) {
    double x1, x2;
    x1 = (-b - Math.sqrt(D)) / (2 * a);
    x2 = (-b + Math.sqrt(D)) / (2 * a);
    System.out.println("x1 = " + x1 + ", x2 = " + x2);
}

public void dEqualsZero(double a, double b) {
    double x;
    x = -b / (2 * a);
    System.out.println("x = " + x);
}

public void dLessThanZero() {
    System.out.println("Equation has no roots");
}
Hər bir metod üçün kod daha qısa və aydın oldu.

Bütün obyektin köçürülməsi

Parametrləri olan bir metodu çağırarkən, bəzən belə kodu görə bilərsiniz:
public void employeeMethod(Employee employee) {
    // Некоторые действия
    double yearlySalary = employee.getYearlySalary();
    double awards = employee.getAwards();
    double monthlySalary = getMonthlySalary(yearlySalary, awards);
    // Продолжение обработки
}

public double getMonthlySalary(double yearlySalary, double awards) {
     return (yearlySalary + awards)/12;
}
Metodda employeeMethoddəyərləri əldə etmək və onları primitiv dəyişənlərdə saxlamaq üçün 2 sətir ayrılmışdır. Bəzən belə dizaynlar 10 sətirə qədər çəkir. Obyektin özünü metoda ötürmək daha asandır, oradan lazımi məlumatları çıxara bilərsiniz:
public void employeeMethod(Employee employee) {
    // Некоторые действия
    double monthlySalary = getMonthlySalary(employee);
    // Продолжение обработки
}

public double getMonthlySalary(Employee employee) {
    return (employee.getYearlySalary() + employee.getAwards())/12;
}
Sadə, qısa və lakonik.

Sahələrin məntiqi qruplaşdırılması və ayrıca sinifdə yerləşdirilməsi

Yuxarıdakı misalların çox sadə olmasına və onlara baxarkən çoxlarının “Bunu əslində kim edir?” sualını verə bilməsinə baxmayaraq, bir çox tərtibatçılar diqqətsizlik, kodu refaktor etmək istəməmələri və ya sadəcə olaraq “Bu edəcək” oxşar struktur səhvləri.

Niyə refaktorinq effektivdir?

Yaxşı bir refaktorinqin nəticəsi kodu oxumaq asan olan proqramdır, proqram məntiqinə edilən dəyişikliklər təhlükəyə çevrilmir və yeni funksiyaların tətbiqi kodu təhlil edən cəhənnəmə deyil, bir neçə gün ərzində xoş bir fəaliyyətə çevrilir. . Proqramı sıfırdan yenidən yazmaq daha asan olarsa, refaktorinqdən istifadə edilməməlidir. Məsələn, komanda kodun təhlili, təhlili və refaktorinqi üçün əmək xərclərini eyni funksionallığı sıfırdan həyata keçirməkdən daha yüksək hesab edir. Və ya refaktorasiya edilməli olan kodun düzəldilməsi çətin olan çoxlu səhvlər var. Proqramçının işində kodun strukturunu necə təkmilləşdirməyi bilmək məcburidir. Yaxşı, JavaRush-da Java proqramlaşdırmasını öyrənmək daha yaxşıdır - praktikaya diqqət yetirən onlayn kurs. Ani yoxlama ilə 1200+ tapşırıq, 20-yə yaxın mini layihə, oyun tapşırıqları - bütün bunlar kodlaşdırmada özünüzü inamlı hiss etməyə kömək edəcək. Başlamaq üçün ən yaxşı vaxt indidir :) Как устроен рефакторинг в Java - 4

Refaktorinqə daha çox dalmaq üçün resurslar

Refaktorinq haqqında ən məşhur kitab “Refaktorinq. Mövcud Kodun Dizaynının Təkmilləşdirilməsi” tərəfindən Martin Fowler. Əvvəlki kitab əsasında yazılmış refaktorinqlə bağlı maraqlı bir nəşr də var - Joshua Kiriewski tərəfindən "Nümunələrlə Refaktorinq". Şablonlardan danışarkən. Refaktorinq zamanı əsas tətbiq dizayn nümunələrini bilmək həmişə çox faydalıdır. Bu böyük kitablar buna kömək edəcək:
  1. "Dizayn Nümunələri" - Eric Freeman, Elizabeth Freeman, Kathy Sierra, Bert Bates tərəfindən Head First seriyasından;
  2. "Oxunan kod və ya bir sənət kimi proqramlaşdırma" - Dastin Boswell, Trevor Faucher.
  3. Gözəl və zərif kodun prinsiplərini əks etdirən Steve McConnell tərəfindən "Mükəmməl Kod".
Bəli, refaktorinq haqqında bir neçə məqalə:
  1. Cəhənnəm işi: köhnə kodun yenidən işlənməsinə başlayaq ;
  2. Refaktorinq ;
  3. Hər kəs üçün refaktorinq .
    Şərhlər
    TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
    GO TO FULL VERSION