سؤال

لدي موقف أحاول فيه الحفاظ على نموذجي وتنفيذي مقترنين بشكل غير محكم قدر الإمكان، ولكنني أواجه موقفًا من المحتمل أن يقترب فيه الاقتران كثيرًا مما أريد.

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

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

مثال مبسط هو:

/// Core classes --

class Car : ICar
{
    public int MakeId { get {...} set { ... } }

    public IMakeInfo Make { get {...} }

    public string Registration { get { ... } set { ... } }

    public int CurrentOwnerId { get { ... } set { ... } }

    public IPerson CurrentOwner { get { ... } }
}

class MakeInfo : IMakeInfo
{
    public string Name { ... }
    public int Id { ... }
    public decimal Weight { ... }
    // etc etc
}

/// Data Access Classes --

class ResolveMake 
{
    public IMakeInfo GetMakeInfo(int id)
    { 
        // Implementation here...
    }

}

كيف يمكنني تمكين Car فئة لتوفير IMakeInfo هل تعترض على أي فئات مستهلكة دون إعلامها مباشرة بفئة ResolveMake؟في المثيل الفعلي الذي أعمل فيه مع فئة Car ليست في نفس مساحة الاسم مثل فئة ResolveMake ولا تحتوي على أي إشارات إلى أي مثيلات لها.

بعض خياراتي:

  • تنفيذ مندوب في Car والتي يمكن توفيرها مع مثيل GetMakeInfo طريقة.
  • نوع من حقن التبعية
  • قم بربط السيارة بشكل وثيق بـ ResolveMake والانتهاء منها.
  • هل هناك أي خيارات أخرى؟

نرحب بأي اقتراحات!

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

المحلول

طرق التمديد?

namespace CarStuff
{
   class Car : ICar
   {
      public int MakeId { get {...} set { ... } }
      // no Make property...
      public string Registration { get { ... } set { ... } }
      public int CurrentOwnerId { get { ... } set { ... } }
      public IPerson CurrentOwner { get { ... } }
   }
}


namespace MakeExts
{
   class ResolveMake
   {
      public static IMakeInfo Make(this Car myCar)
      {
         //implementation here
      }
   }
}

في مكان آخر:

using MakeExts;

Car c = new Car();
Console.WriteLine(c.Make().ToString());

يحرر:لاستخدام أساليب الامتداد في .NET 2.0، تحتاج إلى شيء مثل:

في الأساس، فئة تحتوي على:

namespace System.Runtime.CompilerServices 
{ 
   class ExtensionAttribute : Attribute
   {
   }
 }

و"باستخدام System.Runtime.CompilerServices" منتشرة في الأماكن ذات الصلة.

نصائح أخرى

يبدو لي مثل حقن التبعية.لقد قمت بأشياء مماثلة مع MS PP Unity وحقن المُنشئ بالإضافة إلى حقن الطريقة والممتلكات.بعد ذلك سيكون لفئة السيارة الخاصة بك نوع من حقن IMakeInfo...مثال:

[InjectionMethod]
public void Initialize([Dependency] IMakeInfo makeInfo)
{
  this.MakeInfo = makeInfo;
}

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

إذا كان هذا هو الحال ربما تريد أن تنظر في إنشاء ملف طريقة المصنع الذي يعرف عن السيارات وResolveMake.

وفقًا للقياس الخاص بك، من الواضح أن السيارة تحتاج إلى معرفة بحلول الوقت الذي يُطلق فيه اسم get_Make على اسم IMakeInfo.سأفكر أيضًا في جعل السمة الرئيسية للسيارة.لذلك أعتقد أن تمرير IMakeInfo إلى مُنشئ السيارة (ربما باستخدام IOC) أمر معقول جدًا.إذا كان هذا تشبيهًا جيدًا لشفرتك الحقيقية (كل "سيارة" بها "IMakeInfo" واحد جوهري)، فسأختار هذا.

يمكنك أيضًا استخدام أداة ضبط كما قال يوهان، مرة أخرى مع اللجنة الأولمبية الدولية الاختيارية.السبب الذي يجعلني أفضّل المُنشئ هو ما يبدو كل "السيارة" يجب أن يكون لها "صنع".

في النهاية (نظرًا للقيود التي كنت أعمل ضمنها) استخدمت بالفعل شكلاً مختلفًا لعدد من المواضيع المذكورة أعلاه.

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

class Car 
{
    public void SetLookupProvider(ILookupProvider value) { _lookupProvider = value; }

    public IMakeInfo Make { get { return _lookupProvider.ResolveMake(MakeId); } }

    ....
}

interface ILookupProvider
{
    IMakeInfo ResolveMake(int id);
}

class LookupProvider
{
    public delegate IMakeInfo ResolveMakeDelegate(int id);

    public ResolveMakeDelegate ResolveMakeDel { set { _resolvemake = value; } }

    public IMakeInfo ResolveMake(int id){ return _resolvemake(id); }  
}

ثم بطريقة المصنع ...

ICar returnedObject = new Car(blah, foo, bar, etc);

ILookupProvider luprovider = new LookupProvider();
luprovider.ResolveMakeDel = DataAccessLayer.FunctToGetMakeInfo;

(Car)returnedObject.SetLookupProvider(luprovider).

الآن أنا أول من يعترف بأن هذا ليس الحل الأجمل (كنت سأتبع أساليب الامتداد لو تمكنت من الوصول إلى مترجم 3.0..) ولكنه يبقي فئة السيارة مقترنة بشكل غير محكم بطبقة DataAccess (والتي في حالتي منعت المرجعية الدائرية من الجحيم...).لا تحتاج فئة السيارة إلى معرفة كيفية الحصول على النتيجة، وطريقة المصنع التي تنتج كائنات السيارة في المقام الأول هي الشيء الوحيد الذي يقترن بطبقة الوصول إلى البيانات.

لم أضع علامة على إجابة حتى الآن، سأسمح لعدد قليل من الأشخاص بالتصويت ثم انتقل إلى الأعلى - خاصة وأنني أعتقد أنها جميعها إجابات صالحة (فقط أنني لا أستطيع استخدام أي واحدة بالكامل في هذه الحالة) .

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