شعار ConstructiCat
CodeBust.
تصفح القسم ▾

استبدال كود النوع بالحالة/الاستراتيجية.

المشكلة

لديك نوع مرمز يؤثر على السلوك ولكن لا يمكنك استخدام فئات فرعية للتخلص منه.

الحل

استبدل كود النوع بكائن حالة (state object). إذا كان من الضروري استبدال قيمة حقل بكود نوع، يتم "توصيل" كائن حالة آخر.

##مثال

قبل
class Employee {
  static final int ENGINEER = 0;
  static final int SALESMAN = 1;
  private int type;

  int payAmount() {
    switch (type) {
      case ENGINEER: return monthlySalary;
      case SALESMAN: return monthlySalary + commission;
      default: throw new IllegalStateException();
    }
  }
}
بعد
class Employee {
  private EmployeeType type;

  int payAmount() { return type.payAmount(this); }
  void setType(EmployeeType arg) { type = arg; }
}
abstract class EmployeeType {
  abstract int payAmount(Employee emp);
}
class Engineer extends EmployeeType {
  int payAmount(Employee emp) { return emp.monthlySalary; }
}
class Salesman extends EmployeeType {
  int payAmount(Employee emp) { return emp.monthlySalary + emp.commission; }
}

##لماذا نعيد الهيكلة

لديك كود نوع يؤثر على سلوك فئة ما، وبالتالي لا يمكننا استخدام استبدال رمز النوع بفئة.

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

##الفوائد

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

  • إذا كنت بحاجة إلى إضافة قيمة جديدة لنوع مرمز، فكل ما عليك فعله هو إضافة فئة فرعية جديدة للحالة دون تغيير الكود الحالي (راجع مبدأ الفتح/الإغلاق - Open/Closed Principle).

##كيفية إعادة الهيكلة

  1. استخدم التغليف الذاتي للحقل (Self Encapsulate Field) لإنشاء دالة جلب (getter) للحقل الذي يحتوي على كود النوع.

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

  3. أنشئ فئات فرعية لفئة الحالة لكل قيمة من قيم النوع المرمز. في كل فئة فرعية، أعد تعريف دالة جلب الحقل المرمز بحيث تعيد القيمة المقابلة للنوع المرمز.

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

  5. في الفئة الأصلية، قم بتغيير نوع الحقل المرمز إلى فئة الحالة. في دالة تعيين (setter) الحقل، استدعِ دالة مصنع الحالة للحصول على كائنات حالة جديدة.

  6. الآن يمكنك البدء في نقل الحقول والدوال من الفئة الفائقة إلى الفئات الفرعية المقابلة للحالة (باستخدام إنزال الحقل (Push Down Field) و إنزال الدالة (Push Down Method)).

  7. عندما يتم نقل كل ما يمكن نقله، استخدم استبدال الشرط بتعدد الأشكال (Replace Conditional with Polymorphism) للتخلص من الجمل الشرطية التي تستخدم كود النوع مرة واحدة وإلى الأبد.