سؤال

لقد كنت أفكر في بدء مشروع جديد في C # .NET (4.0RC) لبضعة أيام. ستكون النتيجة النهائية للمشروع مكتبة فئة تتكون من ما يمكنني الآن استدعاء "مقصورة"، واثنين من الواجهات (أو فصول مجردة) و "providerpe" أو اثنين الافتراضي.

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

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

BlogProvider bp = ProviderFactory.GetProvider<BlogProvider>();

ويجب أن تعيد BlogProvider المحدد الحالي، أو NULL إذا لم يكن هناك شيء. كما أريد أن أكون قادرا على تقديم قائمة على جميع مقدمي الخدمات المتاحة من نوع واحد على سبيل المثال

string[] blogproviders = ProviderFactory.GetRegisteredProviders<BlogProvider>();

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

ProviderFactory.SetCurrentProvider<BlogProvider>("ODBCBlogProvider");

هذا يجب أن يجعل BlogProvider الحالي odbcblogprovider، بحيث كنت في المرة القادمة أاتويد ProviderFactoroy.getProvider () يجب إرجاع مثيل ODBCBLOGPROVIDER (أي من الأسباب تحتاج إلى تمديد الفئة الأساسية BlogProvider).

أيضا، يحتاج كل ملف بروفيدارت (أو ProviderBase إذا كنت تحب) للحصول على ProvideryPename (BlogProvider) و ProvideryPedisplayName ("مدونة" أو "مزود المدونة") الفريد من نوعه إلى هذا النمط، وكل مزود يمتد إلى أن هذا المزود يحتاج إلى حساب ServiceDername (ODBCBlogProvider) و ProviderDisPlayName ("ODBC" أو "مدونة ODBC" إلخ). يمكن أن تكون اسم Providername و Providertymame فقط للبساطة تكون هناك أسماء من الدرجة المكتسبة عن طريق الانعكاس.

ربما هذا يعني أنه كنت بحاجة إلى واجهة للحصول على ProviderBase، شيء مثل هذا:

public interface ProviderBase
{
    string ProviderName { get; } // The display-name.
    string Description { get; } // A description of the provider type, like "This provides you with a blog."
}

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

public abstract class BlogProvider : ProviderBase
{
    public string ProviderName
    {
        get { return "Blog"; }
    }

    public string Description
    {
        get { return "This provides you with a blog."; }
    }

    public abstract int GetPostCount();
}

ثم، في مكان ما في الرمز الخاص بي كان علي تشغيل شيء مثل

ProviderFactory.RegisterProviderType(typeof(BlogProvider));

أو خيارا أفضل سيكون قادرا على استخدام السمات مثل هذا:

[Provider("Blog", "This provides you with a blog.")]
public interface BlogProvider
{
    int GetPostCount();
}

لا أرى الحاجة إلى استخدام فئة مجردة بهذا النهج لأنه لا يحتاج أي من الأعضاء في الفصل الأساسي. كما ذهب الحاجة إلى واجهة ProviderBase. الشيء المثالي سيكون السبب الأساسي إذا كان يمكن أن يجد ProviderFacToy مجرد جميع الفئات / الواجهات التي تحتوي على providerattribute، وعزى odbcblogprovider بحاجة فقط إلى تنفيذ BlogProvider، لكنني لست متأكدا من أنني أفعل ذلك، لا سيما عندما يكون متطلبات ذلك يمكن للمقدمين والمحترفين أن يأتون إلى جمعيات خارجية.

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

هناك شرط آخر هو أن مقدمي الخدمة قد يتطلب مقدمي الآخرون للعمل. على سبيل المثال، قد يعمل AudiEngine فقط مع Audicar، ولكن يمكن أن يعمل Audicar تماما مع BMWENGINE.

أيضا (ولست متأكدا من أين وضع ذلك حتى الآن، ربما سمة اختيارية على فئة الموفر نفسها) يجب أن يكون لكل مزود الخيار لتكون Singleton أم لا.

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

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

المحلول

حسنا، يبدو الأمر وكأنه overengineered (بدلا من ذلك، يتوهم بشكل مفرط) IOC / DI. حاوية.

إن فكرة IOC هي نفسها إلى حد كبير، باستثناء أنهم (الحاويات) لا يتطلبون "المتعاونين" لتنفيذ أي واجهات أو استخلاص من الفصول الأساسية:

var builder = new ContainerBuilder();
builder.Register<Car>();
builder.Register<Engine>().As<IEngine>();

var container = builder.Build();

// somewhere in the code
var car = container.Resolve<Car>();

هذا مثال على ذلك باستخدام autofac., ، وهو واحد من عدد لا يحصى من حاويات DI ل C # /. Net.

نصائح أخرى

كما يشير anton، هذا قريب من حاوية IOC / di. مرة أخرى، باستخدام Autofac، يمكنك الحصول على شوط طويل في القيام بشيء من هذا القبيل:

var builder = new ContainerBuilder();
builder.Register<Car>();
builder.Register<BmwEngine>();
builder.Register<AudiEngine>();
builder.Register<DefaultEngine>();
builder.Register<EngineSelector>().As<IEngineSelector>().SingletonScope();

builder.Register(
    c => {
            var selector = c.Resolve<IEngineSelector>();
            switch(selector.CurrentEngine)
            {
                case "bmw":
                    return c.Resolve<BmwEngine>();
                case "audi":
                    return c.Resolve<AudiEngine>();
                default:
                    return c.Resolve<DefaultEngine>();
            }
        }
    ).As<IEngine>().FactoryScoped();

var container = builder.Build();

// somewhere in the code
var selector = container.Resolve<IEngineSelector>();
selector.CurrentEngine = "bmw";

var car = container.Resolve<Car>();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top