نمط طريقة المصنع

في البرمجة القائمة على الأصناف، يعد نمط طريقة المصنع (بالإنجليزية: factory method pattern)‏ نمطًا انشائياً (اي الأنماط المسؤولة عن انشاء كائنات) يستخدم طرق المصنع للتعامل مع مشكلة إنشاء الكائنات دون الحاجة إلى تحديد صنف الكائن الذي سيتم إنشاؤه بالضبط. يتم ذلك بواسطة إنشاء كائنات عن طريق استدعاء طريقة المصنع - إما محدد في واجهة ويتم تنفيذه بواسطة اصناف فرعية، أو يتم تنفيذه في صنف أساسي ويتم تجاوزه اختياريًا بواسطة الاصناف المشتقة - بدلاً من استدعاء مُنشئ.

نظرة عامة

يعد نمط تصميم طريقة المصنع [1] أحد أنماط التصميم "عصابة الأربعة" التي تصف كيفية حل مشكلات التصميم المتكررة لتصميم برامج مرنة وكائنية التوجه قابلة لإعادة الاستخدام، أي الكائنات التي يسهل تنفيذها أو تغييرها أو اختبارها، وإعادة استخدامها.

يتم استخدام نمط (تصميم) طريقة المصنع بدلاً من مُنشئ الصنف العادي للاحتفاظ بمبدأ SOLID للبرمجة، وفصل بناء الكائنات عن الكائنات نفسها. هذه الفكرة لها مزايا ومفيدة للحالات التالية، من بين أمور أخرى: [2]

  • يسمح ببناء الاصناف بمكون من نوع برمجي لم يتم تحديده مسبقًا، ولكن يتم تعريفه فقط في «واجهة» أوا الواجهة، التي يتم تعريفها على أنها نوع ديناميكي.
وبالتالي، على سبيل المثال، يمكن إنشاء صنف Vehicle (مركبة) التي تحتوي على محرك عضو من واجهة محرك IMotor، ولكن لا يوجد نوع محدد من المحرك Motor معرف مسبقًا، عن طريق إخبار مُنشئ السيارة Vehicle constructor باستخدام محرك كهربائي ElectricMotor أو محرك بنزين GasolineMotor. يستدعي كود مُنشئ المركبة Vehicle constructor بعد ذلك طريقة مصنع المحرك، لإنشاء المحرك المطلوب الذي يتوافق مع واجهة IMotor.
  • يسمح ببناء الاصناف الفرعية إلى أحد الأصناف الأبوية الذي لم يتم تحديد نوع مكوناته مسبقًا، ولكن تم تعريفه فقط في واجهة، أو تم تعريفه على أنه نوع ديناميكي.
على سبيل المثال، يمكن لمركبة من الصنف Vehicle التي لديها عضو محدد بنوع ديناميكي، أن تحتوي على اصناف فرعية من النوع ElectricPlane و OldCar تم تصميم كل منها بنوع مختلف من المحركات. يمكن تحقيق ذلك عن طريق بناء الاصناف الفرعية بطريقة مصنع المركبات، مع توفير نوع المحرك. في مثل هذه الحالات قد يكون المنشئ مخفيًا.
  • يسمح لكود أكثر قابلية للقراءة في الحالات التي توجد فيها منشآت متعددة، كل منها لسبب مختلف.
على سبيل المثال إذا كان هناك نوعان من المنشئات Vehicle(make:string, motor:number) و Vehicle(make:string, owner:string, license:number, purchased:date) فإن المنشئ ذو المقروئية الأفضل للاصناف يكون باستخدام Vehicle.CreateOwnership(make:string, owner:string, license:number purchased: date) مقابل Vehicle.Create(make:string, motor:number)

يسمح للصنف بتأجيل التمثيل (إنشاء كائن) إلى الاصناف الفرعية، ومنع التمثيل المباشر لكائن من نوع الصنف الأصل (الأب).

    على سبيل المثال، يمكن منع المركبة Vehicle من أن يتم تمثيلها مباشرة لأنها لا تحتوي على مُنشئ، ويمكن إنشاء الاصناف الفرعية فقط مثل ElectricPlane أو OldCar عن طريق استدعاء طريقة مصنع السيارة (الثابتة)Vehicle في مُنشئ الأصناف الفرعية أو المُهيئ.

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

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

    تعريف

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

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

    يعتمد نمط طريقة المصنع على الوراثة، حيث يتم تفويض إنشاء الكائن إلى الاصناف الفرعية التي تطبق طريقة المصنع لإنشاء الكائنات.[3]

    بناء

    مخطط صنف UML

    رسم تخطيطي لصنف UML لنمط تصميم طريقة المصنع.[4]

    في الرسم التخطيطي لصنف يو-أم-إل أعلاه، الصنف Creator الذي يتطلب كائن Product

    لا يمثل الصنف Product1 مباشرة.

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

    المجردة (factoryMethod) عن طريق إنشاء مثيل لصنف Product1 .

    مثال

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

    هيكل

    Room هو الصنف الأساسي للمنتج النهائي (MagicRoom أو OrdinaryRoom). تعلن شركة MazeGame عن طريقة المصنع المجردة declares the abstract factory methodلإنتاج مثل هذا المنتج الأساسي.

    MagicRoom و OrdinaryRoom هماsubclasses اصناف فرعية MagicRoom للمنتج الأساسي الذي ينفذimplementing المنتج النهائي. وهكذا تقوم factory methodsطرق المصنع decouple callers فصل المتصلين (MazeGame) من تنفيذimplementation أصناف محددة concrete classes. وهذا يجعل عامل التشغيل «الجديد»"new" Operator زائداً عن الحاجة redundant ، ويسمح بالالتزام بمبدأ فتح / إغلاق Open/closed principleويجعل المنتج النهائي أكثر مرونة في حالة التغيير.

    C#

    نفس اكود ل C #

    //Empty vocabulary of actual object
    public interface IPerson
    {
      string GetName();
    }
    
    public class Villager : IPerson
    {
      public string GetName()
      {
        return "Village Person";
      }
    }
    
    public class CityPerson : IPerson
    {
      public string GetName()
      {
        return "City Person";
      }
    }
    
    public enum PersonType
    {
      Rural,
      Urban
    }
    
    /// <summary>
    /// Implementation of Factory - Used to create objects
    /// </summary>
    public class Factory
    {
      public IPerson GetPerson(PersonType type)
      {
        switch (type)
        {
          case PersonType.Rural:
            return new Villager();
          case PersonType.Urban:
            return new CityPerson();
          default:
            throw new NotSupportedException();
        }
      }
    }
    

    في الكود أعلاه، يمكنك رؤية إنشاء واجهة interface واحدة تسمى IPerson وتنفيذين يسمى Villager و CityPerson. استنادًا إلى النوع الذي تم تمريره إلى كائن المصنع، فإننا نعيد الكائن المحدد الأصلي original concrete object كواجهة interface IPerson. طريقة المصنع هي مجرد إضافة إلى صنف المصنع. يقوم بإنشاء كائن من الصنف من خلال واجهاتinterfaces ولكن من ناحية أخرى، فإنه يتيح أيضًا للاصناف الفرعية subclass تحديد الصنف التي يتم إنشاء مثيلinstantiated لها.

    public interface IProduct
    {
      string GetName();
      string SetPrice(double price);
    }
    
    public class Phone : IProduct
    {
      private double _price;
    
      public string GetName()
      {
        return "Apple TouchPad";
      }
    
      public string SetPrice(double price)
      {
        this._price = price;
        return "success";
      }
    }
    
    /* Almost same as Factory, just an additional exposure to do something with the created method */
    public abstract class ProductAbstractFactory
    {
      protected abstract IProduct MakeProduct();
    
      public IProduct GetObject() // Implementation of Factory Method.
      {
        return this.MakeProduct();
      }
    }
    
    public class PhoneConcreteFactory : ProductAbstractFactory
    {
      protected override IProduct MakeProduct()
      {
        IProduct product = new Phone();
        //Do something with the object after you get the object. 
        product.SetPrice(20.30);
        return product;
      }
    }
    

    يمكنك أن ترى أننا استخدمنا MakeProduct في مصنع التحديد concreteFactory. نتيجة لذلك، يمكنك بسهولة استدعاء MakeProduct () منه للحصول على IProduct. يمكنك أيضًا كتابة منطقك المخصص custom logicبعد الحصول على الكائن في طريقة مصنع التحديد concrete Factory Method. يتم إجراء GetObject مجردة في واجهة interface المصنع.

    جافا

    يشبه مثال جافا هذا أحد الأمثلة الموجودة في كتاب أنماط تصميم.


    يستخدم MazeGame الغرف ولكنه يضع مسؤولية إنشاء الغرف على الاصناف الفرعية subclasses التي تنشئ اصناف ملموسة create the concrete classes.. يمكن أن يستخدم وضع اللعبة العاديregular game mode طريقة القالب template method هذه:

    public abstract class Room {
      abstract void connect(Room room);
    }
    
    public class MagicRoom extends Room {
      public void connect(Room room) {}
    }
    
    public class OrdinaryRoom extends Room {
      public void connect(Room room) {}
    }
    
    public abstract class MazeGame {
       private final List<Room> rooms = new ArrayList<>();
    
       public MazeGame() {
         Room room1 = makeRoom();
         Room room2 = makeRoom();
         room1.connect(room2);
         rooms.add(room1);
         rooms.add(room2);
       }
    
       abstract protected Room makeRoom();
    }
    

    في المقتطف أعلاه، MazeGame مُنشئ (constructor) MazeGame طريقة قالب template methodتجعل بعض المنطق شائعًا common logic. يشير إلى factory methodطريقة المصنع makeRoom التي تتضمن إنشاء الغرف بحيث يمكن استخدام الغرف الأخرى في اصناف فرعية subclass. لتنفيذ وضع اللعبة game mode الآخر الذي يحتوي على غرف سحرية magic rooms ، يكفي تجاوز override makeRoom :

    public class MagicMazeGame extends MazeGame {
      @Override
      protected Room makeRoom() {
        return new MagicRoom(); 
      }
    }
    
    public class OrdinaryMazeGame extends MazeGame {
      @Override
      protected Room makeRoom() {
        return new OrdinaryRoom(); 
      }
    }
    
    MazeGame ordinaryGame = new OrdinaryMazeGame();
    MazeGame magicGame = new MagicMazeGame();
    

    بي أتش بي PHP

    يتبع مثال آخر في PHP ، هذه المرة باستخدام تطبيقات الواجهة interface implementations بدلاً من التصنيف الفرعي subclassing (ومع ذلك يمكن تحقيق نفس الشيء من خلال التصنيف الفرعي). من المهم ملاحظة أنه يمكن أيضًا تعريف طريقة المصنع على أنها عامة واستدعاؤها مباشرةً بواسطة كودالعميل client code(على النقيض من مثال Java أعلاه).

    /* Factory and car interfaces */
    
    interface CarFactory
    {
      public function makeCar() : Car;
    }
    
    interface Car
    {
      public function getType() : string;
    }
    
    /* Concrete implementations of the factory and car */
    
    class SedanFactory implements CarFactory
    {
      public function makeCar() : Car
      {
        return new Sedan();
      }
    }
    
    class Sedan implements Car
    {
      public function getType() : string
      {
        return 'Sedan';
      }
    }
    
    /* Client */
    
    $factory = new SedanFactory();
    $car = $factory->makeCar();
    print $car->getType();
    

    بايثون

    نفس مثال جافا.

    from abc import ABC, abstractmethod
    class MazeGame(ABC):
    
      def __init__(self) -> None:
        self.rooms = []
        self._prepare_rooms()
    
      def _prepare_rooms(self) -> None:
        room1 = self.make_room()
        room2 = self.make_room()
    
        room1.connect(room2)
        self.rooms.append(room1)
        self.rooms.append(room2)
    
      def play(self) -> None:
        print('Playing using "{}"'.format(self.rooms[0]))
    
      @abstractmethod
      def make_room(self):
        raise NotImplementedError("You should implement this!")
    class MagicMazeGame(MazeGame):
    
      def make_room(self):
        return MagicRoom()
    class OrdinaryMazeGame(MazeGame):
    
      def make_room(self):
        return OrdinaryRoom()
    class Room(ABC):
      def __init__(self) -> None:
        self.connected_rooms = []
    
      def connect(self, room) -> None:
        self.connected_rooms.append(room)
    class MagicRoom(Room):
      def __str__(self):
        return "Magic room"
    class OrdinaryRoom(Room):
      def __str__(self):
        return "Ordinary room"
    ordinaryGame = OrdinaryMazeGame()
    ordinaryGame.play()
    
    magicGame = MagicMazeGame()
    magicGame.play()
    

    الاستخدامات

    • في ADO. NET ، IDbCommand. CreateParameter هو مثال على استخدام طريقة المصنعfactory method لربط التسلسلات الهرمية للصنف المتوازية connect parallel class hierarchies.
    • في Qt ، QMainWindow :: createPopupMenu هي طريقة مصنع factory method تم التصريحdeclared عنها في إطار عملframework يمكن تجاوزه في رمز التطبيق overridden in application code.
    • في جافا، يتم استخدام العديد من المصانعseveral factories في حزمة package javax.xml.parsers . مثل javax.xml.parsers. DocumentBuilderFactory أو javax.xml.parsers. SAXParserFactory.
    • في HTML5 DOM API ، تحتوي واجهة المستند Document interface على factory method طريقة مصنع createElement لإنشاء عناصر محددة لواجهة interface HTMLElement.

    ملحق: مسرد المصطلحات الإنجليزية

    مَسرد المفردات وفق أقسام المقالة
    المقدمة
    البرمجة القائمة على الأصناف class-based programming
    طرق المصنع البرمجية او دوال المصنع البرمجية factory methods
    واجهة interface
    اصناف فرعية child classes
    صنف أساسي base class
    تجاوزه اختياريًا بواسطة الاصناف المشتقة optionally overridden by derived classes
    المُهيئ initializer
    الممثل instantiator
    اقتران الكود code coupling
    فصل الكود decoupling
    كائن إنشاء composing object
    شؤون الكائن المؤلف composing object's concerns
    النوع البرمجي للمنتج المشتق derived type
    تفويض delegated
    الاصناف الفرعية subclasses
    يمثل instantiate
    الصنف class
    إنشاء تمثيل لصنف محدد منه concrete class is instantiated
    مثيل instantiate
    بتطبيق implements
    المجردة abstract
    إنشاء مثيل ل instantiating

    انظر أيضا

    المراجع

    1. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994)، Design Patterns: Elements of Reusable Object-Oriented Software، Addison Wesley، ص. 107ff، ISBN 0-201-63361-2، مؤرشف من الأصل في 18 مايو 2020.{{استشهاد بكتاب}}: صيانة CS1: أسماء متعددة: قائمة المؤلفون (link)
    2. "The Factory Method design pattern - Problem, Solution, and Applicability"، w3sDesign.com، مؤرشف من الأصل في 18 مايو 2020، اطلع عليه بتاريخ 17 أغسطس 2017.
    3. Freeman, Eric؛ Freeman, Elisabeth؛ Kathy, Sierra؛ Bert, Bates (2004)، Hendrickson؛ Loukides (المحررون)، Head First Design Patterns، O'REILLY، ج. 1، ص. 162، ISBN 978-0-596-00712-6، مؤرشف من الأصل (paperback) في 30 أبريل 2020، اطلع عليه بتاريخ 12 سبتمبر 2012.
    4. "The Factory Method design pattern - Structure and Collaboration"، w3sDesign.com، مؤرشف من الأصل في 18 مايو 2020، اطلع عليه بتاريخ 12 أغسطس 2017.

    روابط خارجية

    • بوابة علم الحاسوب
    This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.