نمط Factory لتصميم القوالب - ما هو وما فائدته

مبرمج طموحمنذ 5 سنوات

السلام عليكم، أهلاً بمعشر المبرمجين!

في هذا المقال أحاول شرح واحد من أشهر أنماط تصميم البرامج (software design patterns) وهو ما يسمى نمط المصنع أو (factory design pattern).

ملاحظة: أنا أفترض معرفة مسبقة بلغة Java أو بأحد اللغات كائنية التوجه (OO)، ومعرفة بسيطة بلغة UML.

ما هو نمط التصميم Factory؟

نمط Factory هو بكل بساطة أحد أنماط التصميم الإنشائية (creational) التي تُعنى بتصميم عملية إنشاء القوالب (classes) وكيفية التواصل فيما بينها.

لماذا نستخدم نمط Factory؟

هذا النمط يسهل علينا عملية إنشاء كائنات (instantiating objects) بحيث يكون هناك (methods) معينة خاصة بالمصنع تمكننا من إنشاء كائنات جديدة دون الحاجة لمعرفة نوع القالب (class) للكائن الذي سوف ننشئه.

حسناً، حتى تتضح لك فائدة هذا النمط سأضرب لك مثالاً يوضح لك ذلك:

تخيل أنك تريد إنشاء قالب من نوع abstract اسمه Car وترغب في إنشاء ثلاثة أنواع منها لكل نوع قالب خاص به. ولنفترض مثلاً أن الأنواع هي سيارة رياضية، سيارة صغيرة، وسيارة سيدان.

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

إنشاء الكائنات بدون استخدام نمط Factory

ولكن، ما المشكلة في هذه الطريقة؟ حسناً، هناك مشكلتين رئيستين:

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

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

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

طريقة تنفيذ نمط Factory

الآن وقد عرفنا المشاكل الرئيسة التي تنتج عن استخدام الطريقة التقليدية في إنشاء الكائنات، دعونا نلقي نظرة على الطريقة التي يستخدمها نمط Factroy في إنشاء الكائنات.

عملية إنشاء الكائنات باستخدام نمط Factory

هكذا ستبدو القوالب في نمط Factory وهكذا ستكون عملية إنشاء الكائنات.

دعونا الآن ننظر كيف ستبدو الشيفرة المصدرية:

بدايةً، قالب Car:

public abstract class Car {
    public abstract int getPrice();
}

وبعدها القوالب التي ترث قالب Car وهي كالتالي:

class SedanCar extends Car {
    @Override
    public int getPrice() {
        return 100000;
    }
}

class SmallCar extends Car {
    @Override
    public int getPrice() {
        return 50000;
    }
}

class SportCar extends Car {
    @Override
    public int getPrice() {
        return 250000;
    }
}

وأخيراً قالب المصنع (وهو الذي يهمنا هنا) الذي ننشئ به الكائنات:

public class CarFactory {
    public static Car createCar(String type){
        switch(type){
            case "Sedan":
                return new SedanCar();
            case "Small":
                return new SmallCar();
            case "Sport":
                return new SportCar();
            default:
                return null;
        }
    }
}

لاحظ الآن كيف أن قالب المصنع (CarFactory) قام بإخفاء التفاصيل الداخلية لأنواع السيارات التي لدينا بإرجاع كل نوع على حدة بحسب المطلوب في المعامل type.

المصنع هنا يعمل عمل الواجهة البرمجية (API) تماماً، ولكي تتضح لك الصورة أكثر انظر إلى الطريقة التي يحصل فيها العميل على كائنات Car:

public class Client {
    public static void main(String[] args) {
        Car sedan = CarFactory.createCar("Sedan");
        Car small = CarFactory.createCar("Small");
        Car sport = CarFactory.createCar("Sport");
        
        System.out.println("Price of Sedan Car: $" + sedan.getPrice());
        System.out.println("Price of Small Car: $" + small.getPrice());
        System.out.println("Price of Sport Car: $" + sport.getPrice());
    }
}

لن يشغل العميل نفسه بكيفية إنشاء كائن من نوع Sedan مثلاً، لأن كل التفاصيل هذه أخفاها عنه قالب CarFactory.

ماذا لو كان ال(constructor) الخاص بقالب SedanCar أكثر تعقيداً؟ لا يهم، فهذا ما تكفل به نمط المصنع هنا ولن يكون من شأن العميل في شيء.

ولو رغب العميل في تغيير بعض خصائص السيارة فيما بعد، فسيكون لديه (setters) تمكنه من ذلك طبعاً.

خلاصة وتعقيب

هناك بعض الأنماط الإنشائية الأخرى التي قد يهمك أن تبحث فيها أكثر مثل Abstract Factory ومثل Builder وغيرها. 

أتمنى في النهاية أن أكون قد وفقتُ في إيصال المعلومة لك، وأن أكون قد فتحت لك آفاق جديدة لتبحث وتتعمق فيها.

تركتُ في الأسفل بعض المصادر والمراجع التي استفدت منها.

 

مصادر:

Java Factory Pattern Explained - HowToDoInJava

Factory method pattern - Wikipedia

Factory Design Pattern in Java - JournalDev

 

حقوق الصورة محفوظة لأصحابها.

1
إعجاب
5124
مشاهدات
0
مشاركة
1
متابع

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !