سؤال

أنا من أشد المعجبين بـ NTiers بسبب خيارات التطوير الخاصة بي، وبالطبع فهي لا تناسب كل السيناريوهات.

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

هيكل طبقة العمل العادي الخاص بي هو هذا (العرض الأساسي له):

  • عمل
    • خدمات
      • فوكومبونينت
        • فوهيلبرز
        • FooWorkflows
      • BahComponent
        • BahHelpers
        • سير العمل باه
    • خدمات
      • شائع
      • ExceptionHandlers
      • المستوردين
      • إلخ...

الآن، مع ما ورد أعلاه، أصبح لدي إمكانية وصول رائعة لحفظ كائن Foo وكائن Bah مباشرة، عبر مساعديهما.

يمنحني XXXHelpers إمكانية الوصول إلى حفظ الكائنات المعنية وتحريرها وتحميلها، ولكن أين أضع المنطق لحفظ الكائنات ذات الكائنات الفرعية.

على سبيل المثال:

لدينا الكائنات أدناه (ليست أشياء جيدة جدًا أعرفها)

  • موظف
  • تفاصيل الموظف
  • عضوية الموظف
  • ملف تعريف الموظف

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

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

ماذا كنت ستفعل؟وأنا أعلم أن هذا كله تفضيل.

تخطيط أكثر تفصيلا

تحتوي مسارات العمل على كافة الاستدعاءات مباشرة إلى DataRepository، على سبيل المثال:

public ObjectNameGetById(Guid id)
{
    return DataRepository.ObjectNameProvider.GetById(id);
}

ومن ثم وصول مزود المساعدين إلى سير العمل:

public ObjectName GetById(Guid id)
{
    return loadWorkflow.GetById(id);
}

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

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

اسم المشروع.الأساسية

projectName.Business
    - Interfaces
        - IDeleteWorkflows.cs
        - ILoadWorkflows.cs
        - ISaveWorkflows.cs
        - IServiceHelper.cs
        - IServiceViewHelper.cs
    - Services
        - ObjectNameComponent
            - Helpers
                - ObjectNameHelper.cs
            - Workflows
                - DeleteObjectNameWorkflow.cs
                - LoadObjectNameWorkflow.cs
                - SaveObjectNameWorkflow.cs
    - Utilities
        - Common
            - SettingsManager.cs
            - JavascriptManager.cs
            - XmlHelper.cs
            - others...

        - ExceptionHandlers
            - ExceptionManager.cs
            - ExceptionManagerFactory.cs
            - ExceptionNotifier.cs


projectName.Data
    - Bases
        - ObjectNameProviderBase.cs
    - Helpers
        - ProviderHelper.cs
    - Interfaces
        - IProviderBase.cs
    - DataRepository.cs

projectName.Data.Model
    - Database.edmx

projectName.Entities (Entities that represent the DB tables are created by EF in .Data.Model, this is for others that I may need that are not related to the database)
    - Helpers
        - EnumHelper.cs

اسم المشروع.العرض

(يعتمد على اسم التطبيق)

projectName.web
projectName.mvc
projectName.admin

المشاريع الاختبارية

projectName.Business.Tests
projectName.Data.Test
هل كانت مفيدة؟

المحلول

+1 لسؤال مثير للاهتمام.

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

لكن أولاً، النهج المفضل لدي هنا هو البنية المؤسسية الشائعة جدًا والتي سأحاول تسليط الضوء عليها باختصار، ولكن هناك المزيد من العمق هناك.إنه يتطلب بعض التغييرات الجذرية في التفكير - استخدام NHibernate أو Entity Framework للسماح لك بالاستعلام عن نموذج الكائن الخاص بك مباشرةً والسماح لـ ORM بالتعامل مع أشياء مثل التعيين من وإلى قاعدة البيانات وعلاقات التحميل البطيئة وما إلى ذلك.سيسمح لك القيام بذلك بتنفيذ كل منطق عملك ضمن نموذج المجال.

أولاً المستويات (أو المشاريع في الحل الخاص بك)؛

YourApplication.Domain

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

YourApplication.Data

فئات المستودع - هذه هي الفئات التي تتعامل مع الحصول على الجذر (الجذور) المجمعة لنموذج المجال الخاص بك.

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

YourApplication.Workflow

  • يمكن أن يُطلق عليه أيضًا اسم YourApplication.Services، ولكن يمكن الخلط بينه وبين خدمات الويب
  • تدور هذه الطبقة حول العمليات الذرية المعقدة والمترابطة - فبدلاً من وجود مجموعة من الأشياء التي يجب استدعاؤها في طبقة العرض التقديمي، وبالتالي زيادة الاقتران، يمكنك دمج هذه العمليات في مهام سير العمل أو الخدمات.
  • من الممكن أن تتمكن من الاستغناء عن هذا في العديد من التطبيقات.

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

YourApplication.YourChosenPresentationTier

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

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

إذا لم تكن بحاجة إلى توزيع طبقاتك، فتذكر أن القاعدة الأولى للبنيات الموزعة هي عدم التوزيع، إذًا ستستهلك سير العمل/الخدمات والمستودعات مباشرةً من داخل asp.net وmvc وwpf وwinforms وما إلى ذلك.

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

في تطبيق سطح المكتب، WPF أو winforms، سيكون لديك سياق لكل نموذج.يضمن ذلك إجراء التعديلات على كيانات المجال في مربع حوار التحرير الذي يقوم بتحديث النموذج ولكن لا يصل إلى قاعدة البيانات (على سبيل المثال:تم تحديد إلغاء) لا تتداخل مع السياقات الأخرى أو ما هو أسوأ من ذلك أن يستمر الأمر عن طريق الخطأ.

حقن التبعية

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

مساحات الأسماء تلك

أخيرًا، السبب وراء فقدان مساحة أسماء المساعدين هو، في النموذج أعلاه، أنك لا تحتاج إليها، ولكن أيضًا، مثل مساحات أسماء الأدوات المساعدة، فإنها تمنح المطورين الكسالى ذريعة لعدم التفكير في مكان وجود جزء من التعليمات البرمجية بشكل منطقي.MyApp.Helpers.* وMyApp.Utility.* يعني فقط أنه إذا كان لدي بعض التعليمات البرمجية، فلنقل معالج الاستثناء الذي ربما ينتمي منطقيًا إلى MyApp.Data.Repositories.Customers (ربما يكون مرجع العميل ليس استثناءً فريدًا)، وهو كسول يمكن للمطور وضعه في MyApp.Utility.CustomerRefNotUniqueException دون الحاجة إلى التفكير حقًا.

إذا كان لديك تعليمات برمجية لنوع إطار عمل مشترك وتحتاج إلى إكماله، فأضف مشروع MyApp.Framework ومساحات الأسماء ذات الصلة.إذا كنت تضيف رابطًا لنموذج جديد، فضعه في MyApp.Framework.Mvc، وإذا كانت وظيفة تسجيل شائعة، فضعه في MyApp.Framework.Logging وما إلى ذلك.في معظم الحالات، لا ينبغي أن تكون هناك حاجة إلى تقديم مساحة اسم أداة مساعدة أو مساعدة.

يتم إحتوائه

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

هتاف توني

نصائح أخرى

يوجد رسم تخطيطي لطيف ووصف في هذه الصفحة حول تخطيط التطبيق ، ينظر Alhtough إلى أسفل المقال ، لا ينقسم التطبيق إلى طبقات فعلية (مشروع منفصل) - مستودع إطار الكيان POCO

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