CodeGym /مدونة جافا /Random-AR /كيف تعمل إعادة البناء في جافا
John Squirrels
مستوى
San Francisco

كيف تعمل إعادة البناء في جافا

نشرت في المجموعة
عندما تتعلم كيفية البرمجة، فإنك تقضي الكثير من الوقت في كتابة التعليمات البرمجية. يعتقد معظم المطورين المبتدئين أن هذا هو ما سيفعلونه في المستقبل. هذا صحيح جزئيًا، لكن وظيفة المبرمج تتضمن أيضًا صيانة التعليمات البرمجية وإعادة هيكلتها. اليوم سنتحدث عن إعادة الهيكلة. كيف تعمل إعادة البناء في جافا - 1

إعادة البناء على CodeGym

تتم تغطية إعادة البناء مرتين في دورة CodeGym: توفر المهمة الكبيرة فرصة للتعرف على إعادة الهيكلة الحقيقية من خلال الممارسة، ويساعدك الدرس الخاص بإعادة الهيكلة في IDEA على التعمق في الأدوات الآلية التي ستجعل حياتك أسهل بشكل لا يصدق.

ما هي إعادة الهيكلة؟

إنه يغير بنية الكود دون تغيير وظائفه. على سبيل المثال، لنفترض أن لدينا طريقة تقارن رقمين وترجع صحيحًا إذا كان الأول أكبر وخطأ فيما عدا ذلك:
public boolean max(int a, int b) {
    if(a > b) {
        return true;
    } else if (a == b) {
        return false;
    } else {
        return false;
    }
}
هذا رمز غير عملي إلى حد ما. حتى المبتدئين نادرًا ما يكتبون شيئًا كهذا، ولكن هناك فرصة. لماذا تستخدم if-elseالكتلة إذا كان بإمكانك كتابة الطريقة المكونة من 6 أسطر بشكل أكثر إيجازًا؟
public boolean max(int a, int b) {
     return a > b;
}
الآن لدينا طريقة بسيطة وأنيقة تؤدي نفس العملية كما في المثال أعلاه. هذه هي الطريقة التي تعمل بها إعادة البناء: يمكنك تغيير بنية التعليمات البرمجية دون التأثير على جوهرها. هناك العديد من أساليب وتقنيات إعادة الهيكلة التي سنلقي نظرة عليها عن كثب.

لماذا تحتاج إلى إعادة الهيكلة؟

هناك عدة أسباب. على سبيل المثال، لتحقيق البساطة والإيجاز في التعليمات البرمجية. يعتقد أنصار هذه النظرية أن الكود يجب أن يكون موجزًا ​​قدر الإمكان، حتى لو كانت هناك حاجة إلى عشرات الأسطر من التعليقات لفهمه. المطورون الآخرون مقتنعون بضرورة إعادة هيكلة التعليمات البرمجية لجعلها مفهومة بأقل عدد من التعليقات. يتبنى كل فريق موقفه الخاص، لكن تذكر أن إعادة الهيكلة لا تعني التخفيض . والغرض الرئيسي منه هو تحسين هيكل التعليمات البرمجية. يمكن تضمين عدة مهام في هذا الغرض العام:
  1. تعمل إعادة البناء على تحسين فهم التعليمات البرمجية المكتوبة بواسطة مطورين آخرين.
  2. يساعد في العثور على الأخطاء وإصلاحها.
  3. يمكنه تسريع سرعة تطوير البرمجيات.
  4. وبشكل عام، فإنه يحسن تصميم البرمجيات.
إذا لم يتم تنفيذ إعادة البناء لفترة طويلة، فقد يواجه التطوير صعوبات، بما في ذلك التوقف الكامل للعمل.

"رائحة الكود"

عندما يتطلب الكود إعادة البناء، يقال أنه يحتوي على "رائحة". بالطبع، ليس حرفيًا، لكن مثل هذا الكود لا يبدو جذابًا للغاية. سنستكشف أدناه تقنيات إعادة البناء الأساسية للمرحلة الأولية.

فئات وأساليب كبيرة بشكل غير معقول

يمكن أن تكون الفصول والأساليب مرهقة، ومن المستحيل العمل معها بفعالية على وجه التحديد بسبب حجمها الضخم.

فئة كبيرة

تحتوي هذه الفئة على عدد كبير من أسطر التعليمات البرمجية والعديد من الطرق المختلفة. عادةً ما يكون من الأسهل على المطور إضافة ميزة إلى فئة موجودة بدلاً من إنشاء فئة جديدة، وهذا هو سبب نمو الفئة. كقاعدة عامة، يتم حشر الكثير من الوظائف في مثل هذه الفئة. في هذه الحالة، من المفيد نقل جزء من الوظيفة إلى فئة منفصلة. سنتحدث عن هذا بمزيد من التفصيل في القسم الخاص بتقنيات إعادة البناء.

طريقة طويلة

تنشأ هذه "الرائحة" عندما يضيف المطور وظائف جديدة إلى إحدى الطرق: "لماذا يجب أن أضع فحص المعلمات في طريقة منفصلة إذا كان بإمكاني كتابة الكود هنا؟"، "لماذا أحتاج إلى طريقة بحث منفصلة للعثور على الحد الأقصى "عنصر في مصفوفة؟ دعنا نحتفظ به هنا. سيكون الكود أكثر وضوحًا بهذه الطريقة"، وغيرها من المفاهيم الخاطئة.

هناك قاعدتان لإعادة هيكلة الطريقة الطويلة:

  1. إذا كنت ترغب في إضافة تعليق عند كتابة طريقة ما، فيجب عليك وضع الوظيفة في طريقة منفصلة.
  2. إذا كانت إحدى الطرق تستغرق أكثر من 10 إلى 15 سطرًا من التعليمات البرمجية، فيجب عليك تحديد المهام والمهام الفرعية التي تؤديها ومحاولة وضع المهام الفرعية في طريقة منفصلة.

هناك عدة طرق للتخلص من الطريقة الطويلة:

  • نقل جزء من وظائف الطريقة إلى طريقة منفصلة
  • إذا كانت المتغيرات المحلية تمنعك من نقل جزء من الوظيفة، فيمكنك نقل الكائن بأكمله إلى طريقة أخرى.

استخدام الكثير من أنواع البيانات البدائية

تحدث هذه المشكلة عادةً عندما يتزايد عدد الحقول في الفصل الدراسي مع مرور الوقت. على سبيل المثال، إذا قمت بتخزين كل شيء (العملة، التاريخ، أرقام الهواتف، إلخ) بأنواع بدائية أو ثوابت بدلاً من الكائنات الصغيرة. في هذه الحالة، قد تكون الممارسة الجيدة هي نقل مجموعة منطقية من الحقول إلى فئة منفصلة (فئة الاستخراج). يمكنك أيضًا إضافة طرق إلى الفصل لمعالجة البيانات.

هناك عدد كبير جدًا من المعلمات

هذا خطأ شائع إلى حد ما، خاصة بالاشتراك مع طريقة طويلة. يحدث هذا عادةً إذا كانت الطريقة تحتوي على الكثير من الوظائف، أو إذا كانت الطريقة تنفذ خوارزميات متعددة. من الصعب جدًا فهم القوائم الطويلة من المعلمات، كما أن استخدام الأساليب مع مثل هذه القوائم أمر غير مريح. ونتيجة لذلك، فمن الأفضل تمرير كائن بأكمله. إذا كان الكائن لا يحتوي على بيانات كافية، فيجب عليك استخدام كائن أكثر عمومية أو تقسيم وظائف الطريقة بحيث تقوم كل طريقة بمعالجة البيانات المرتبطة منطقيًا.

مجموعات البيانات

غالبًا ما تظهر مجموعات البيانات المرتبطة منطقيًا في التعليمات البرمجية. على سبيل المثال، معلمات اتصال قاعدة البيانات (عنوان URL، اسم المستخدم، كلمة المرور، اسم المخطط، وما إلى ذلك). إذا لم يكن من الممكن إزالة حقل واحد من قائمة الحقول، فيجب نقل هذه الحقول إلى فئة منفصلة (فئة الاستخراج).

الحلول التي تنتهك مبادئ OOP

تحدث هذه "الروائح" عندما ينتهك المطور تصميم OOP المناسب. يحدث هذا عندما لا يفهم هو أو هي قدرات OOP بشكل كامل ويفشل في استخدامها بشكل كامل أو صحيح.

عدم استغلال الميراث

إذا كانت الفئة الفرعية تستخدم فقط مجموعة فرعية صغيرة من وظائف الفئة الأصلية، فستفوح منها رائحة التسلسل الهرمي الخاطئ. عندما يحدث هذا، عادةً لا يتم تجاوز الأساليب غير الضرورية أو أنها تطرح استثناءات. تشير فئة واحدة ترث فئة أخرى إلى أن الفئة الفرعية تستخدم جميع وظائف الفئة الأصلية تقريبًا. مثال على التسلسل الهرمي الصحيح: كيف تعمل إعادة البناء في جافا - 2مثال على التسلسل الهرمي غير الصحيح: كيف تعمل إعادة البناء في جافا - 3

بيان التبديل

ما يمكن أن يكون الخطأ في switchالبيان؟ إنه أمر سيء عندما يصبح معقدًا للغاية. المشكلة ذات الصلة هي وجود عدد كبير من ifالعبارات المتداخلة.

فئات بديلة مع واجهات مختلفة

فئات متعددة تفعل الشيء نفسه، ولكن أساليبها لها أسماء مختلفة.

المجال المؤقت

إذا كان الفصل يحتوي على حقل مؤقت لا يحتاجه الكائن إلا في بعض الأحيان عند تعيين قيمته، وهو فارغ أو لا سمح الله nullبقية الوقت، فإن رائحة الكود كريهة. هذا قرار تصميم مشكوك فيه.

الروائح التي تجعل التعديل صعباً

هذه الروائح أكثر خطورة. الروائح الأخرى تجعل فهم التعليمات البرمجية أكثر صعوبة، لكنها تمنعك من تعديلها. عندما تحاول تقديم أي ميزات جديدة، يستقيل نصف المطورين، ويصاب النصف الآخر بالجنون.

التسلسلات الهرمية الميراث الموازية

تتجلى هذه المشكلة عندما يتطلب التصنيف الفرعي لفئة ما إنشاء فئة فرعية أخرى لفئة مختلفة.

التبعيات الموزعة بشكل موحد

تتطلب أي تعديلات منك البحث عن جميع استخدامات الفصل (التبعيات) وإجراء الكثير من التغييرات الصغيرة. تغيير واحد - تعديلات في العديد من الفئات.

شجرة معقدة من التعديلات

هذه الرائحة هي عكس الرائحة السابقة: فالتغيرات تؤثر على عدد كبير من الأساليب في الفصل الواحد. كقاعدة عامة، يكون لمثل هذه التعليمات البرمجية تبعية متتالية: يتطلب تغيير إحدى الطرق إصلاح شيء ما في طريقة أخرى، ثم في الطريقة الثالثة، وهكذا. فئة واحدة - العديد من التغييرات.

"روائح القمامة"

فئة من الروائح الكريهة إلى حد ما تسبب الصداع. رمز قديم عديم الفائدة وغير ضروري. لحسن الحظ، تعلمت IDEs وLinters الحديثة التحذير من مثل هذه الروائح.

عدد كبير من التعليقات في الطريقة

تحتوي الطريقة على الكثير من التعليقات التوضيحية في كل سطر تقريبًا. يرجع هذا عادةً إلى خوارزمية معقدة، لذا من الأفضل تقسيم الكود إلى عدة طرق أصغر وإعطائها أسماء توضيحية.

رمز مكرر

تستخدم الفئات أو الأساليب المختلفة نفس مجموعات التعليمات البرمجية.

فئة كسول

يأخذ الفصل وظائف قليلة جدًا، على الرغم من أنه تم التخطيط له ليكون كبيرًا.

كود غير مستخدم

لا يتم استخدام فئة أو طريقة أو متغير في الكود وهو وزن ثقيل.

الاتصال المفرط

تتميز هذه الفئة من الروائح بعدد كبير من العلاقات غير المبررة في الكود.

الأساليب الخارجية

تستخدم الطريقة البيانات من كائن آخر في كثير من الأحيان أكثر من البيانات الخاصة بها.

العلاقة الحميمة غير المناسبة

يعتمد الفصل على تفاصيل التنفيذ لفئة أخرى.

مكالمات صفية طويلة

تستدعي إحدى الفئات فئة أخرى، والتي تطلب البيانات من فئة ثالثة، والتي تحصل على البيانات من فئة رابعة، وهكذا. مثل هذه السلسلة الطويلة من المكالمات تعني الاعتماد الكبير على البنية الطبقية الحالية.

فئة تاجر المهام

الفصل الدراسي مطلوب فقط لإرسال مهمة إلى فصل آخر. ربما ينبغي إزالته؟

تقنيات إعادة الهيكلة

سنناقش أدناه تقنيات إعادة البناء الأساسية التي يمكن أن تساعد في التخلص من روائح التعليمات البرمجية الموصوفة.

استخراج فئة

يؤدي الفصل عددًا كبيرًا جدًا من الوظائف. ويجب نقل بعضهم إلى فئة أخرى. على سبيل المثال، لنفترض أن لدينا فئة Humanتقوم أيضًا بتخزين عنوان المنزل ولديها طريقة تُرجع العنوان الكامل:
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();
    }
 }
من الممارسات الجيدة وضع معلومات العنوان والطريقة المرتبطة بها (سلوك معالجة البيانات) في فئة منفصلة:
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();
   }
}

استخراج طريقة

إذا كانت إحدى الطرق تحتوي على بعض الوظائف التي يمكن عزلها، فيجب عليك وضعها في طريقة منفصلة. على سبيل المثال، طريقة لحساب جذور المعادلة التربيعية:
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");
    }
}
نقوم بحساب كل خيار من الخيارات الثلاثة الممكنة بطرق منفصلة:
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");
}
أصبح رمز كل طريقة أقصر بكثير وأسهل للفهم.

تمرير كائن بأكمله

عندما يتم استدعاء عملية مع المعلمات، قد ترى في بعض الأحيان رمزًا مثل هذا:
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;
}
يحتوي employeeMethodعلى سطرين كاملين مخصصين لتلقي القيم وتخزينها في متغيرات بدائية. في بعض الأحيان يمكن أن تستغرق هذه التركيبات ما يصل إلى 10 أسطر. من الأسهل بكثير تمرير الكائن نفسه واستخدامه لاستخراج البيانات الضرورية:
public void employeeMethod(Employee employee) {
    // Some actions
    double monthlySalary = getMonthlySalary(employee);
    // Continue processing
}

public double getMonthlySalary(Employee employee) {
    return (employee.getYearlySalary() + employee.getAwards())/12;
}

بسيطة ومختصرة وموجزة.

تجميع الحقول بشكل منطقي ونقلها إلى حقول منفصلة classDespiteحقيقة أن الأمثلة أعلاه بسيطة للغاية، وعندما تنظر إليها، قد يتساءل الكثير منكم، "من يفعل هذا؟"، العديد من المطورين يرتكبون مثل هذه الأخطاء الهيكلية بسبب الإهمال، عدم الرغبة في إعادة صياغة الكود، أو مجرد موقف "هذا جيد بما فيه الكفاية".

لماذا تعتبر إعادة الهيكلة فعالة

نتيجة لإعادة الهيكلة الجيدة، يصبح لدى البرنامج تعليمات برمجية سهلة القراءة، ولا يعد احتمال تغيير منطقه أمرًا مخيفًا، كما أن إدخال ميزات جديدة لا يصبح جحيمًا لتحليل التعليمات البرمجية، ولكنه بدلاً من ذلك تجربة ممتعة لبضعة أيام . لا يجب عليك إعادة البناء إذا كان من الأسهل كتابة برنامج من الصفر. على سبيل المثال، لنفترض أن فريقك يقدر أن العمالة المطلوبة لفهم التعليمات البرمجية وتحليلها وإعادة تصميمها ستكون أكبر من تنفيذ نفس الوظيفة من البداية. أو إذا كان الكود المراد إعادة هيكلته يحتوي على الكثير من المشكلات التي يصعب تصحيحها. تعد معرفة كيفية تحسين بنية التعليمات البرمجية أمرًا ضروريًا في عمل المبرمج. ويتم تعلم البرمجة بلغة Java بشكل أفضل على CodeGym، وهي الدورة التدريبية عبر الإنترنت التي تركز على الممارسة. أكثر من 1200 مهمة مع التحقق الفوري، وحوالي 20 مشروعًا صغيرًا، ومهام ألعاب - كل هذا سيساعدك على الشعور بالثقة في البرمجة. أفضل وقت للبدء هو الآن :)

الموارد اللازمة لمزيد من الانغماس في إعادة البناء

أشهر كتاب عن إعادة البناء هو "إعادة البناء. تحسين تصميم الكود الموجود" بقلم مارتن فاولر. هناك أيضًا منشور مثير للاهتمام حول إعادة البناء، استنادًا إلى كتاب سابق: "إعادة البناء باستخدام الأنماط" بقلم جوشوا كيريفسكي. عند الحديث عن الأنماط... عند إعادة البناء، من المفيد دائمًا معرفة أنماط التصميم الأساسية. ستساعدك هذه الكتب الممتازة في هذا: الحديث عن الأنماط... عند إعادة البناء، من المفيد دائمًا معرفة أنماط التصميم الأساسية. هذه الكتب الممتازة ستساعد في هذا:
  1. "أنماط التصميم" لإريك فريمان، وإليزابيث روبسون، وكاثي سييرا، وبيرت بيتس، من سلسلة Head First
  2. "فن البرمجة المقروءة" لداستن بوزويل وتريفور فوشيه
  3. "اكتمل الكود" بقلم ستيف ماكونيل، والذي يحدد مبادئ الكود الجميل والأنيق.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION