سؤال

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

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

ودعونا نسمي طريقة منفصلة واحدة لتغيير هذا الكائن أ Mutator. Mutators يتم تطبيقها مرة واحدة (عموما) ولديهم طريقة داخلية مثل apply(Target& target, ...), ، الذي يثير على الفور تغيير حالة الكائن (في الواقع ، إنها نوع من الكائنات الوظيفية).

كما يمكن استيعابها بسهولة السلاسل وتطبيق واحد تلو الآخر (Mutator m1, m2, ...) ؛ كما يمكن أن يستمدوا من بعض الأساسي BasicMutator مع virtual void apply(...) طريقة.

لقد قدمت فصولًا تسمى InnerMutator و ExplicitMutator التي تختلف من حيث الوصول - أولاً يمكن أيضًا تغيير الحالة الداخلية من الكائن ويجب إعلانه كصديق (friend InnerMutator::access;).


في تلك المشاريع تحول منطقي إلى العمل بالطريقة التالية:

  1. قم بإعداد الطفرات المتاحة ، اختر أيًا للتطبيق
  2. إنشاء وتعيين object لبعض الحالة المصممة
  3. foreach (mutator) mutator.apply(object);

الآن السؤال.

يتحول هذا المخطط إلى العمل بشكل جيد و (إلي) يبدو كعينة من نمط تصميم غير قياسي ولكن مفيد.

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

هل يمكن حل هذا الموقف من حيث Mutators أو هل يمكنك المشورة بعض النمط البديل بنفس النتيجة؟

شكرًا.

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

المحلول

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

لماذا تحتاج إلى تجميع الطفرات ، على سبيل المثال؟ يمكن للمرء مجرد الكتابة:

template <class T>
void mutate(T& t)
{
    t.mutate1(...);
    t.mutate2(...);
    t.mutate3(...);
}

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

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

foreach(v.begin(), v.end(), attack && burn && drain);

لقد كان أنيقًا حقًا وبدا أنه ذكي حقًا بالنسبة لي في ذلك الوقت ، وكان فعالًا جدًا لأنه أنشأ كائنات وظيفية جديدة على الطيران (لا توجد آليات وقت تشغيل) ، ولكن عندما رأى زملائي في العمل ، ظنوا أنني مجنون. عند العودة إلى الوراء ، كنت أحاول حشر كل شيء في برمجة نمط وظيفي والتي لها فائدتها ولكن ربما لا ينبغي أن تكون مبالغ فيها في C ++. كان من السهل كتابة:

BOOST_FOR_EACH(Something& something, v)
{
    attack(something);
    burn(something);
    drain(something);
}

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

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

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

نصائح أخرى

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top