سؤال

حسنًا، هذه مشكلة أواجهها.

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

  1. قم بتوفير خاصية الاتصال التي تم تعيينها بواسطة المتصل قبل استدعاء الطريقة.هذا له بعض العيوب.

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

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

    • توفير أ Connection يبدو أن الملكية (بالنسبة لي، على أي حال) تصرخ من أجل المقابل Transaction ملكية.يؤدي هذا إلى إنشاء حمل إضافي في الوثائق، حيث يتعين عليك توضيح متى تم استخدام المعاملة ومتى لم يتم استخدامها.

    من ناحية أخرى، يبدو أن مايكروسوفت تفضل نموذج المجموعة والاستدعاء بأكمله.

  2. يتطلب تمرير الاتصال كوسيطة للأسلوب.هذا له بعض المزايا والعيوب:

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

    • في حين أنه لا يزال يتعين التحقق من صحة الاتصال (والمعاملة) قبل الاستخدام، إلا أن المرجع إليه موجود فقط طوال مدة استدعاء الأسلوب.

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

    • إذا كانت الطريقة لا تتطلب معاملة (على سبيل المثال طريقة تسترد البيانات من قاعدة البيانات فقط)، فلا توجد معاملة مطلوبة.لا يوجد نقص في الوضوح بسبب توقيع الطريقة.

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

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

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

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

لو كنت مكاني ماذا ستفعل؟

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

المحلول

وهنا نمط ثالث يجب مراعاته:

  • قم بإنشاء فئة تسمى ConnectionScope، والتي توفر الوصول إلى الاتصال
  • يمكن لأي فصل في أي وقت إنشاء ConnectionScope
  • يحتوي ConnectionScope على خاصية تسمى Connection، والتي تقوم دائمًا بإرجاع اتصال صالح
  • أي (وكل) ​​ConnectionScope يتيح الوصول إلى نفس كائن الاتصال الأساسي (ضمن نطاق ما، ربما داخل نفس مؤشر الترابط أو العملية)

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

المزيد من التفاصيل:

  • في C#، أوصي بأن يقوم ConnectionScope بتنفيذ IDisposable، وبهذه الطريقة يمكن لفئاتك كتابة تعليمات برمجية مثل "استخدام ( varscope = new ConnectionScope() )" ومن ثم يمكن لـ ConnectionScope تحرير الاتصال (إذا كان ذلك مناسبًا) عندما يتم تدميره
  • إذا كان بإمكانك تقييد نفسك باتصال واحد لكل مؤشر ترابط (أو عملية) فيمكنك بسهولة تعيين سلسلة الاتصال في متغير ثابت [مؤشر ترابط] في ConnectionScope
  • يمكنك بعد ذلك استخدام العد المرجعي للتأكد من إعادة استخدام اتصالك الفردي عندما يكون مفتوحًا بالفعل ويتم تحرير الاتصالات عندما لا يستخدمها أحد

محدث:فيما يلي بعض نماذج التعليمات البرمجية المبسطة:

public class ConnectionScope : IDisposable
{
   private static Connection m_Connection;
   private static int m_ReferenceCount;

   public Connection Connection
   {
      get
      {
          return m_Connection;
      }
   }

   public ConnectionScope()
   {
      if ( m_Connection == null )
      {
          m_Connection = OpenConnection();
      }
      m_ReferenceCount++;
   }

   public void Dispose()
   {
      m_ReferenceCount--;
      if ( m_ReferenceCount == 0 )
      {
         m_Connection.Dispose();
         m_Connection = null;
      }
   }
}

مثال على الكود لكيفية استخدام أحد (أي) من فصولك الدراسية له:

using ( var scope = new ConnectionScope() )
{
   scope.Connection.ExecuteCommand( ... )
}

نصائح أخرى

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

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