نمط تصميم "مجموعة التعريف الوسيطة" - معروف تحت اسم آخر؟

StackOverflow https://stackoverflow.com/questions/401720

سؤال

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

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

لذا فإن ما يسهله هو نوع من التجميع المشترك والمترابط بشكل غير محكم، حيث قد تحتوي العديد من السيارات على WankelEngine ولكن لا يوجد سوى كائن تعريف WankelEngine واحد فقط (ويمكن لـ EngineTypeBroker استبدال هذا الكائن، مما يؤدي إلى الاستفادة من الاقتران غير المحكم في شكل وقت التشغيل المحسن).

بعض عناصر هذا النمط كما أستخدمه (الاستمرار في استخدام EngineType كمثال):

  1. توجد دائمًا وظائف IsEngineType(x) وEngineType(x)، لتحديد ما إذا كانت القيمة المحددة هي مفتاح مرجعي صالح لـ EngineType ولاسترجاع كائن تعريف EngineType المطابق لمفتاح مرجعي، على التوالي.
  2. أسمح دائمًا بأشكال متعددة من المفاتيح المرجعية لـ EngineType معين، ودائمًا على الأقل اسم سلسلة وكائن التعريف نفسه، وفي أغلب الأحيان معرف عدد صحيح، وأحيانًا أنواع الكائنات التي تجمع EngineType.يساعد هذا في تصحيح الأخطاء، ويجعل التعليمات البرمجية أكثر مرونة، وفي حالتي الخاصة، يخفف الكثير من مشكلات التوافق مع الإصدارات السابقة المتعلقة بالممارسات القديمة.(كانت الطريقة المعتادة التي يستخدمها الأشخاص للقيام بكل هذا، في سياق هذا المشروع، هي تحديد التجزئات لكل خاصية قد يمتلكها EngineType والبحث عن الخصائص حسب المفتاح المرجعي.)
  3. عادة، كل مثيل تعريف هو فئة فرعية من فئة عامة لنوع التعريف هذا (أي.WankelEngine يرث EngineType).يتم الاحتفاظ بملفات الفئة لكائنات التعريف في دليل مثل /Def/EngineType (أي.ستكون فئة WankelEngine هي /Def/EngineType/WankelEngine).لذلك يتم تجميع التعريفات ذات الصلة معًا، وتشبه ملفات الفئة ملفات التكوين الخاصة بـ EngineType، ولكن مع القدرة على تعريف التعليمات البرمجية (لا توجد عادةً في ملفات التكوين).

بعض نماذج الكود الكاذب التوضيحية التافهة:

class Car {

    attribute Name;
    attribute EngineTypeCode;

    object GetEngineTypeDef() {
        return EngineTypeBroker->EngineType(this->GetEngineTypeCode());
    }

    string GetDescription() {
        object def = this->GetEngineTypeDef();
        return "I am a car called " . this->GetName() . ", whose " .
            def->GetEngineTypeName() . " engine can run at " .
            def->GetEngineTypeMaxRPM() . " RPM!";
    }

}

إذن، هل هناك اسم لهذا؟

هل كانت مفيدة؟

المحلول

SingletonRegistry

صدقني أم لا.كنت أفكر في نفس الشيء هذا الصباح.

لقد استخدمت هذا النمط من قبل ولكني لم أجد مرجعًا له ولا أعرف كيفية تسميته.

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

آخر مرة استخدمتها كانت لاسترداد البيانات من مصادر مختلفة.

كان لدي حوالي 50 جدول قاعدة بيانات (اجعلها 10) ولدي "جدول" أمامي حيث سيتم عرض البيانات، ولكن يمكن أن تأتي البيانات من أي من هذه المصادر ويتطلب كل منها منطقًا مختلفًا (الاستعلامات والوصلات والمفاتيح) ، إلخ.)

كانت هذه الواجهة الأمامية "قابلة للتكوين" لذا لم أتمكن من معرفة القيم التي سيتم عرضها وأي القيم الأخرى لن تظهر.

كان الحل هو استخدام columnName (في الواجهة الأمامية) كمفتاح، والحصول على المثيل الصحيح لإنشاء الاستعلام الصحيح.

تم تثبيت هذا في خريطة التجزئة في البداية وتم استرجاعه لاحقًا من جدول قاعدة البيانات.

وكان الرمز مثل هذا:

class DataFetcher {
    abstract Object getData( Object id );
}

class CustomerNameDataFetcher extends DataFetcher {
    Object getData( Object customerId ) { 
        // select name from customer where id = ? 
     }
}

class CompanyAdressDataFetcher extends DataFetcher { 
     Object getData( Object customerId ) { // don't ask why.
          // select name from company , customer where customer.co = company.co and cu = ?  etc.
     }
} 

class ProductColor extends DataFetcher { 
     Object getData( Object x ) { 
     // join from customer to color, to company to season to a bunch of table where id = ? 
}

// And the list goes on.

استخدمت كل فئة فرعية منطقًا مختلفًا.

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

عندما حدد المستخدم الأعمدة التي يريد رؤيتها، استخدمت اسم العمود والمعرف لجلب البيانات.

تم تثبيت جميع DataFetchers في الفصل الأصلي (لم أرغب في الحصول على فصل منفصل لهذا) في طريقة الفصل.

class DataFetcher {
    abstract Object getData( Object id );

    private static final Map fetchers = new HashMap();static { 
        fetchers.put("customer.name", new CustomerNameDataFetcher() );
        fetchers.put("company.address", new CompanyAdressDataFetcher () );
        fetchers.put("product.color", new ProductColor () );
        ...
    }
    public static DataFetcher getFetcher( String id ) { 
        return fetchers.get( id );
    }      

}

في النهاية، لملء جدول الواجهة الأمامية، أسميه هكذا:

كود مزيف

 for each row in table 
      for each column in row
          column.text = DataFetcher.getFetcher( column.id ).getData( row.id )
       end
 end

هل هو مثل هذا؟أم أنني أخطأت في قراءة وصفك ووصفي مختلف تمامًا.

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

نصائح أخرى

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

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

يبدو لي وكأنه مزيج من GoF Builder وPrototype وربما وزن الريشة.

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

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

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

يناقش فريق GoF تركيب الأنماط في أنماط أكبر، وMVC على وجه الخصوص عبارة عن مجموع ثلاثة أنماط أخرى.يبدو أنك فعلت شيئا من هذا القبيل.

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

ما لديك هو خريطة، ويعرف أيضًا باسم القاموس.لديك لمسة فريدة من نوعها من خلال تعيين مفاتيح متعددة لكائن واحد.

لماذا هي خريطة:

  • احتفظ بالمفتاح
  • استخدم المفتاح للاستعلام عن قيمة من بعض هياكل البيانات.

يمكنك العثور على تطبيقات في:

  • المحكمة الخاصة بلبنان (تشمل:خريطة)
  • جافا (استيراد:java.util.Dictionary)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top