CodeGym /Java blog /Véletlen /Hogyan működik a refaktorálás a Java-ban
John Squirrels
Szint
San Francisco

Hogyan működik a refaktorálás a Java-ban

Megjelent a csoportban
Ahogy megtanulod a programozást, sok időt töltesz kódírással. A legtöbb kezdő fejlesztő úgy gondolja, hogy ezt fogja tenni a jövőben. Ez részben igaz, de a programozói munkához hozzátartozik a kód karbantartása és újrafeldolgozása is. Ma a refaktorálásról fogunk beszélni. Hogyan működik a refaktorálás a Java nyelven - 1

Refaktorálás a CodeGym-en

A CodeGym tanfolyamon kétszer szerepel a refaktorálás: A nagy feladat lehetőséget ad arra, hogy gyakorláson keresztül megismerkedj a valódi refaktorálással, az IDEA refaktorálásról szóló lecke pedig segít elmerülni az életedet hihetetlenül megkönnyítő automatizált eszközökben.

Mi az a refaktorálás?

Megváltoztatja a kód szerkezetét anélkül, hogy megváltoztatná a funkcionalitását. Tegyük fel például, hogy van egy metódusunk, amely 2 számot hasonlít össze, és igaz értéket ad vissza , ha az első nagyobb, egyébként pedig hamis :

    public boolean max(int a, int b) {
        if(a > b) {
            return true;
        } else if (a == b) {
            return false;
        } else {
            return false;
        }
    }
Ez egy meglehetősen nehézkes kód. Még a kezdők is ritkán írnak ilyesmit, de van rá esély. Miért használjunk if-elseblokkot, ha a 6 soros metódust tömörebben le tudod írni?

 public boolean max(int a, int b) {
      return a > b;
 }
Most van egy egyszerű és elegáns módszerünk, amely ugyanazt a műveletet hajtja végre, mint a fenti példa. A refaktorálás így működik: megváltoztatod a kód szerkezetét anélkül, hogy a lényegét befolyásolnád. Számos refaktorálási módszer és technika létezik, amelyeket közelebbről megvizsgálunk.

Miért van szükség refaktorálásra?

Ennek több oka is van. Például a kód egyszerűsége és rövidsége érdekében. Ennek az elméletnek a hívei úgy vélik, hogy a kódnak a lehető legtömörebbnek kell lennie, még akkor is, ha több tucat sornyi megjegyzésre van szükség a megértéséhez. Más fejlesztők meg vannak győződve arról, hogy a kódot át kell alakítani, hogy a minimális számú megjegyzéssel érthető legyen. Minden csapat elfogadja a saját álláspontját, de ne feledje, hogy az átalakítás nem jelent csökkentést . Fő célja a kód szerkezetének javítása. Ebbe az általános célba több feladat is beletartozhat:
  1. Az újrafaktorálás javítja a más fejlesztők által írt kódok megértését.
  2. Segít megtalálni és kijavítani a hibákat.
  3. Felgyorsíthatja a szoftverfejlesztés sebességét.
  4. Összességében javítja a szoftvertervezést.
Ha a refaktorálást hosszabb ideig nem végzik el, a fejlesztés nehézségekbe ütközhet, beleértve a munka teljes leállását is.

"A kód szaga"

Ha a kód átalakítást igényel, akkor azt mondják, hogy "illata" van. Természetesen nem szó szerint, de ez a kód valóban nem tűnik túl vonzónak. Az alábbiakban megvizsgáljuk az alapvető refaktorálási technikákat a kezdeti szakaszban.

Indokolatlanul nagy osztályok és módszerek

Az osztályok és módszerek nehézkesek lehetnek, nem lehet hatékonyan dolgozni velük éppen hatalmas méretük miatt.

Nagy osztály

Egy ilyen osztálynak hatalmas számú kódsora és sok különböző módszere van. A fejlesztők általában könnyebben hozzáadhatnak egy funkciót egy meglévő osztályhoz, nem pedig újat hoznak létre, ezért az osztály növekszik. Általában túl sok funkcionalitás van egy ilyen osztályban. Ebben az esetben segít a funkcionalitás egy részének áthelyezése egy külön osztályba. Erről részletesebben a refaktorálási technikákról szóló részben fogunk beszélni.

Hosszú módszer

Ez a "szag" akkor keletkezik, amikor a fejlesztő új funkcionalitást ad egy metódushoz: "Miért tegyem egy paraméterellenőrzést külön metódusba, ha ide írhatom a kódot?", "Miért kell külön keresési módszer a maximum megtalálásához elem egy tömbben? Maradjunk itt. A kód így világosabb lesz", és más hasonló tévhitek.

Két szabály van a hosszú metódusok refaktorálására:

  1. Ha van kedve hozzáfűzni egy megjegyzést egy metódus írásakor, akkor a funkcionalitást külön metódusba kell helyeznie.
  2. Ha egy metódus több mint 10-15 sornyi kódot vesz igénybe, meg kell határoznia az általa végrehajtott feladatokat és részfeladatokat, és meg kell próbálnia külön metódusba helyezni a részfeladatokat.

Számos módja van a hosszú módszer megszüntetésének:

  • Helyezze át a metódus funkcióinak egy részét egy külön metódusba
  • Ha a helyi változók megakadályozzák a funkcionalitás egy részének áthelyezését, akkor az egész objektumot áthelyezheti egy másik metódusba.

Sok primitív adattípus használata

Ez a probléma általában akkor jelentkezik, ha az osztályban lévő mezők száma idővel növekszik. Például, ha mindent (pénznemet, dátumot, telefonszámokat stb.) primitív típusokban vagy konstansokban tárolunk kis objektumok helyett. Ebben az esetben a jó gyakorlat az lenne, ha a mezők logikai csoportosítását egy külön osztályba (kivonat osztályba) helyeznénk át. Az osztályhoz metódusokat is hozzáadhat az adatok feldolgozásához.

Túl sok paraméter

Ez meglehetősen gyakori hiba, különösen hosszú módszerrel kombinálva. Általában akkor fordul elő, ha egy metódus túl sok funkcióval rendelkezik, vagy ha egy módszer több algoritmust valósít meg. A paraméterek hosszú listáit nagyon nehéz megérteni, és az ilyen listákkal rendelkező módszerek használata kényelmetlen. Ennek eredményeként jobb, ha egy egész objektumot áthalad. Ha egy objektumnak nincs elég adata, használjon általánosabb objektumot, vagy ossza fel a metódus funkcionalitását úgy, hogy mindegyik metódus logikailag kapcsolódó adatokat dolgozzon fel.

Adatcsoportok

A logikailag összefüggő adatok csoportjai gyakran megjelennek a kódban. Például az adatbázis-kapcsolat paraméterei (URL, felhasználónév, jelszó, sémanév stb.). Ha egyetlen mező sem távolítható el a mezők listájából, akkor ezeket a mezőket egy külön osztályba (kivonat osztályba) kell áthelyezni.

Az OOP elveit sértő megoldások

Ezek a "szagok" akkor jelentkeznek, amikor a fejlesztő megsérti a megfelelő OOP-tervet. Ez akkor fordul elő, ha nem érti teljesen az OOP képességeit, és nem használja azokat teljesen vagy megfelelően.

Az öröklés használatának elmulasztása

Ha egy alosztály a szülőosztály függvényeinek csak egy kis részhalmazát használja, akkor rossz hierarchia szaga van. Amikor ez megtörténik, általában a felesleges módszereket egyszerűen nem írják felül, vagy kivételeket dobnak. Az egyik osztály egy másik öröklése azt jelenti, hogy az utódosztály a szülőosztály szinte minden funkcióját használja. Példa a helyes hierarchiára: Hogyan működik a refaktorálás a Java-ban - 2Példa hibás hierarchiára: Hogyan működik az újrafaktorálás a Java nyelven - 3

Kapcsoló nyilatkozat

Mi lehet a baj egy nyilatkozattal switch? Rossz, ha nagyon bonyolulttá válik. Ehhez kapcsolódó probléma a beágyazott utasítások nagy száma if.

Alternatív osztályok különböző interfészekkel

Több osztály is ugyanazt a dolgot csinálja, de metódusaik különböző nevük van.

Ideiglenes mező

Ha egy osztálynak van egy ideiglenes mezője, amelyre egy objektumnak csak alkalmanként van szüksége, amikor az értéke be van állítva, és üres, vagy ne adj isten, nulla többi időben, akkor a kód szaga van. Ez megkérdőjelezhető tervezési döntés.

Szagok, amelyek megnehezítik a módosítást

Ezek a szagok komolyabbak. Más szagok főként megnehezítik a kód megértését, de ezek megakadályozzák, hogy módosítsák azt. Amikor új funkciókat próbál bevezetni, a fejlesztők fele kilép, a fele pedig megőrül.

Párhuzamos öröklődési hierarchiák

Ez a probléma akkor jelentkezik, ha egy osztály alosztályozásához egy másik alosztályt kell létrehoznia egy másik osztályhoz.

Egyenletesen elosztott függőségek

Bármilyen módosításhoz meg kell keresnie az osztály összes felhasználási területét (függőségét), és sok apró változtatást kell végrehajtania. Egy változás – szerkesztések sok osztályban.

A módosítások összetett fája

Ez a szag az előző ellentéte: a változtatások egy osztályban számos metódust érintenek. Az ilyen kódok általában lépcsőzetes függőséggel rendelkeznek: az egyik módszer megváltoztatásához meg kell javítani valamit a másikban, majd a harmadikban és így tovább. Egy osztály - sok változás.

"Szemétszagok"

A szagok meglehetősen kellemetlen kategóriája, amely fejfájást okoz. Haszontalan, felesleges, régi kód. Szerencsére a modern IDE-k és linterek megtanultak figyelmeztetni az ilyen szagokra.

Nagy számú megjegyzés egy módszerben

Egy módszer szinte minden sorához sok magyarázó megjegyzés tartozik. Ez általában egy összetett algoritmusnak köszönhető, ezért jobb, ha a kódot több kisebb metódusra bontjuk, és magyarázó neveket adunk nekik.

Megkettőzött kód

A különböző osztályok vagy metódusok ugyanazokat a kódblokkokat használják.

Lusta osztály

Egy osztály nagyon kevés funkciót tölt be, bár nagynak tervezték.

Nem használt kód

Osztály, metódus vagy változó nem szerepel a kódban, és önsúly.

Túlzott kapcsolat

A szagoknak ezt a kategóriáját nagyszámú indokolatlan kapcsolat jellemzi a kódban.

Külső módszerek

Egy metódus sokkal gyakrabban használ egy másik objektumból származó adatokat, mint a saját adatait.

Nem megfelelő intimitás

Egy osztály egy másik osztály megvalósítási részleteitől függ.

Hosszú órahívások

Az egyik osztály hívja a másikat, amely adatokat kér a harmadiktól, amely adatokat kap a negyediktől, és így tovább. A hívások ilyen hosszú láncolata nagy függőséget jelent az aktuális osztálystruktúrától.

Feladatkereskedő osztály

Egy osztály csak egy feladat másik osztályba küldéséhez szükséges. Talán el kellene távolítani?

Refaktorálási technikák

Az alábbiakban megvitatjuk azokat az alapvető refaktorálási technikákat, amelyek segíthetnek kiküszöbölni a leírt kódszagokat.

Kivonat egy osztályt

Egy osztály túl sok funkciót lát el. Néhányat át kell helyezni egy másik osztályba. Tegyük fel például, hogy van egy Humanosztályunk, amely otthoni címet is tárol, és van egy metódusa, amely a teljes címet adja vissza:

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();
    }
 }
Célszerű a címinformációt és a kapcsolódó metódust (adatfeldolgozási viselkedés) egy külön osztályba helyezni:

 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();
    }
 }

Kivonat egy módszert

Ha egy metódusnak van olyan funkciója, amely elkülöníthető, helyezze el egy külön metódusba. Például egy olyan módszer, amely egy másodfokú egyenlet gyökereit számítja ki:

    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");
        }
    }
A három lehetséges opció mindegyikét külön módszerrel számítjuk ki:

    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");
    }
Mindegyik módszer kódja sokkal rövidebb és könnyebben érthető lett.

Egy egész objektum elhaladása

Amikor egy metódust paraméterekkel hívják meg, néha ehhez hasonló kódot láthat:

 public void employeeMethod(Employee employee) {
     // Some actions
     double yearlySalary = employee.getYearlySalary();
     double awards = employee.getAwards();
     double monthlySalary = getMonthlySalary(yearlySalary, awards);
     // Continue processing
 }
 
 public double getMonthlySalary(double yearlySalary, double awards) {
      return (yearlySalary + awards)/12;
 }
2 egész sora van employeeMethodaz értékek fogadására és primitív változókban való tárolására. Néha az ilyen konstrukciók akár 10 sort is igénybe vehetnek. Sokkal egyszerűbb magát az objektumot átadni és felhasználni a szükséges adatok kinyerésére:

 public void employeeMethod(Employee employee) {
     // Some actions
     double monthlySalary = getMonthlySalary(employee);
     // Continue processing
 }
 
 public double getMonthlySalary(Employee employee) {
     return (employee.getYearlySalary() + employee.getAwards())/12;
 }

Egyszerű, rövid és tömör.

A mezők logikai csoportosítása és külön csoportosítása classDespiteaz a tény, hogy a fenti példák nagyon egyszerűek, és ha megnézzük őket, sokan feltehetik a kérdést: "Ki csinálja ezt?", sok fejlesztő követ el ilyen szerkezeti hibákat figyelmetlenségből. nem hajlandó a kódot átalakítani, vagy egyszerűen az "elég jó" hozzáállás.

Miért hatékony a refaktorálás?

A jó átdolgozás eredményeként egy program könnyen olvasható kóddal rendelkezik, a logikájának megváltoztatásának lehetősége nem ijesztő, és az új funkciók bevezetése nem válik kódelemzési pokollá, hanem kellemes élményt jelent néhány napig . Nem szabad refaktorálni, ha egyszerűbb lenne a semmiből programot írni. Tegyük fel például, hogy a csapat becslése szerint a kód megértéséhez, elemzéséhez és újrafeldolgozásához szükséges munka több lesz, mintha ugyanazt a funkciót a semmiből valósítaná meg. Vagy ha az újrafaktorálandó kódnak sok olyan problémája van, amelyeket nehéz hibakeresni. A programozó munkájában elengedhetetlen a kód szerkezetének javításának ismerete. A Java nyelvű programozást pedig a CodeGym-en lehet a legjobban elsajátítani, a gyakorlatot hangsúlyozó online tanfolyamon. 1200+ feladat azonnali ellenőrzéssel, körülbelül 20 miniprojekt, játékfeladatok – mindez segít abban, hogy magabiztosan érezze magát a kódolásban. A legjobb időpont most kezdeni :)

Erőforrások, amelyek segítségével még jobban elmerülhet az átalakításban

A leghíresebb könyv az átalakításról Martin Fowler "Refaktoring. Improving the Design of Existing Code". Van egy érdekes kiadvány is az átalakításról, egy korábbi könyv alapján: Joshua Kerievsky "Refactoring Using Patterns". Ha már a mintáknál tartunk... Refaktoráláskor mindig nagyon hasznos az alapvető tervezési minták ismerete. Ebben segítenek ezek a kiváló könyvek: Ha már a mintákról beszélünk... Refaktoráláskor mindig nagyon hasznos az alapvető tervezési minták ismerete. Ezek a kiváló könyvek segítenek ebben:
  1. Eric Freeman, Elizabeth Robson, Kathy Sierra és Bert Bates "Design Patterns" a Head First sorozatból
  2. "Az olvasható kód művészete" Dustin Boswell és Trevor Foucher
  3. Steve McConnell "Code Complete", amely lefekteti a szép és elegáns kód alapelveit.
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION