كيفية التعامل مع الاتصال بين طبقات المجال وقاعدة البيانات؟

StackOverflow https://stackoverflow.com/questions/549305

سؤال

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

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

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

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

المحلول

غابرييل، وهذا ما يسمى "مشكلة مطابقة المعاوقة". هناك العديد من الحلول، بدءًا من الحلول ذات الوزن الثقيل مثل وحدات وحدات كيان J2EE وحتى Ruby ActiveRecord وحتى ترميز الاتصال اليدوي ببساطة.

تحديث

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

أي من هذه الأنواع من المشكلات المعمارية تكون مدفوعة بمتطلبات غير وظيفية مثل الأداء؛بالإضافة إلى ذلك، هناك مشكلة تتعلق بالصحة هنا، حيث أنك تريد التأكد من إجراء التحديثات بالترتيب الصحيح.لذلك، سوف تحتاج إلى التفكير في عبء العمل, ، وهذا يعني نمط الاستخدام في التطبيق الواقعي.مع أخذ ذلك في الاعتبار، لديك في الأساس مشكلتان:أولاً، قد لا يتم تعيين أنواع البيانات الأساسية في تطبيقك بشكل صحيح إلى قاعدة البيانات (على سبيل المثال، ما هي خاصية VARCHAR الممثلة في التعليمات البرمجية الخاصة بك؟)، وثانيًا، قد لا يتم تعيين نموذج المجال الخاص بك بشكل واضح لنموذج قاعدة البيانات الخاصة بك.

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

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

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

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

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

نصائح أخرى

هناك تمييز بين نموذج المجال وتنفيذها. فقط لأن طرازك يظهر علاقة Person ---> Campaign ---> Event لا يعني أنه يجب عليك تطبيقه بهذه الطريقة. iOW، يظهر طرازك تحليلك وتصميمك بطريقة موجهة للكائنات، ولكن يمكنك تنفيذ هذا النموذج في OOP وهو محدود في مدى جودة إعادة النسخ المتماثل لهذا النموذج في التعليمات البرمجية.

النظر في ما يلي.

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

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

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

لذلك، في الكود (pseudo-c #) ...

namespace DomainLayer
{
    interface IDomainListener 
    {
        void PersonCreated(Person person);
    }

    class Person
    {
        private string name;

        public Person(string name)
        {
            this.name = name;
        }

        public string Name
        {
            get { return name; }
        }
    }

    class Domain 
    {
        private IDomainListener listener;

        public Domain(IDomainListener listener) {
            this.listener = listener;
        }

        public void CreatePerson(string name) {
            Person person = new Person(name);
            listener.PersonCreated(person);
        }
    }
}


namespace PersistenceLayer
{
    interface IPersistenceListener
    {
        void PersonDataSaved(int id, object data);
    }

    class Persistence
    {
        private IPersistenceListener listener;

        public Persistence(IPersistenceListener listener) 
        {
            this.listener = listener;
        }

        public void SaveData(object data)
        {
            int id = ...; // save data and return identifier
            listener.DataSaved(id, data);
        }
    }
}

namespace MyApplication
{
    class MyController : IDomainListener, IPersistenceListener
    {
        public void CreatePersonButton_Clicked()
        {
            Domain domain = new Domain(this);
            domain.CreatePerson(NameTextbox.Text);
        }

        public void PersonCreated(Person person)
        {
            Persistence persistence = new Persistence(this);
            persistence.SavePersonData(person.Name);
        }

        public void DataSaved(int id, object data)
        {
            // display data on UI
        }
    }   
}

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

عند النقر فوق "إنشاء زر"، تقوم وحدة التحكم بإنشاء Domain كائن الواجهة لطبقة المجال وتسجل نفسها كمستمع. ثم يستدعي CreatePerson الطريقة التي تنفسذة Person ثم تعلن أن هذا قد تم القيام به، وعقب المثال الجديد. تحكم يستجيب لهذا الإعلان في PersonCreated التنفيذ حيث يطرد واجهة من طبقة الثبات وتسجل نفسها مستمع مرة أخرى. ثم يستدعي SaveData الطريقة التي DataSaved عندما يكتمل. يعرض تنفيذ هذه الطريقة البيانات على واجهة المستخدم.

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

العودة إلى مشكلتك الخاصة، يمكنك الحصول على طريقة FindPerson على الثبات، الذي سيعلن PersonFound(int id). وبعد سيكون الاستجابة من جانب وحدة التحكم هو استدعاء طبقة الثبات لاسترداد البيانات حول الحملة والأحداث، ثم اتصل بطبقة المجال مع تلك البيانات لبناء Person.

نعتذر عن الاجابة الطويلة...

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

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

أود أن أنظر إلى طبقات تجريد البيانات المستخدمة من قبل phpcake و symfony.

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