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

ليست هناك حاجة لنقل جميع مجالات نموذج Person
إذا كان في جزء التطبيق الذي يهمنا ، فنحن بحاجة فقط إلى حقلين: login
password
. إذا كان من المريح بالنسبة لنا النظر إلى Person
كمستخدم للتطبيق ، فبعد الخريطة ، يمكننا بسهولة استخدام نموذج باسم نتفهمه.
دعنا نفكر في الطرق الملائمة والعملية لتعيين البيانات باستخدام مثال تحويل نموذجين Person
Salary
من طبقة Source
إلى نموذج طبقة Destination
.

على سبيل المثال ، النماذج مبسطة. يحتوي Person
على Salary
في طبقتين من الطلب.
في هذا الرمز ، إذا كان لديك نفس النموذج ، فقد يكون من المفيد مراجعة طبقات التطبيق وعدم استخدام التعيين.
الطريقة رقم 1: أساليب معين
مثال:
class PersonSrc( private val name: String, private val salary: SalarySrc ) { fun mapToDestination() = PersonDst( name, salary.mapToDestination()
الطريقة الأسرع والأسهل. هو الذي يستخدم في CleanArchitecture Kotlin ( مثال على رسم الخرائط ).
زائد هي القدرة على إخفاء الحقول. يمكن أن تكون الحقول في PersonSrc
private
، PersonSrc
البرمجية التي تستخدم فئة PersonSrc
مستقلة عنها ، مما يعني أن تماسك الكود قد انخفض.
هذا الرمز أسرع في الكتابة وأسهل في التعديل - إعلانات المجال واستخدامها في مكان واحد. لا حاجة للتشغيل حول المشروع وتعديل ملفات مختلفة عند تغيير حقول الفصل.
ومع ذلك ، هذا الخيار هو أصعب للاختبار. تحتوي طريقة معين لفئة PersonSrc PersonSrc
استدعاء الأسلوب SalarySrc
. لذلك سيكون اختبار تعيين Person
فقط بدون تعيين Salary
أكثر صعوبة. سوف تضطر إلى استخدام moki لهذا الغرض.
قد تنشأ مشكلة أخرى إذا ، وفقًا لمتطلبات البنية ، لا يمكن لطبقات التطبيق معرفة بعضها البعض: أي في فئة Src
لطبقة ، لا يمكنك العمل مع طبقة Dst
والعكس. في هذه الحالة ، لا يمكن استخدام هذا الإصدار من التعيين.
في المثال الذي تم النظر فيه ، تعتمد طبقة Src
على طبقة Dst
ويمكنها إنشاء فئات من هذه الطبقة. بالنسبة إلى الموقف المعاكس (عندما يكون Dst
يعتمد على Src
) ، يكون الخيار مع أساليب المصنع الثابتة مناسبًا:
class PersonDst( private val name: String, private val salary: SalaryDst ) { companion object { fun fromSource( src: PersonSrc ) = PersonDst(src.name, SalaryDst.fromSource(src.salary)) } } class SalaryDst( private val amount: Int ) { companion object { fun fromSource(src: SalarySrc) = SalaryDst(src.amount) } }
يتم التعيين داخل فئات طبقة Dst
، مما يعني أن هذه الفئات لا تكشف كل خصائصها وهيكلها إلى الكود الذي يستخدمها.
إذا كانت هناك طبقة واحدة في التطبيق تعتمد على الآخر وتم نقل البيانات بين طبقات التطبيق في كلا الاتجاهين ، فمن المنطقي استخدام أساليب المصنع الثابتة مع طرق معين.
ملخص طريقة التعيين:
+
بسرعة كتابة التعليمات البرمجية ، ورسم الخرائط هو دائما في متناول اليد
+
تعديل سهل
+
اتصال رمز منخفض
-
اختبار وحدة صعبة (moki اللازمة)
-
لا يسمح دائما بهندسة العمارة
الطريقة 2: وظائف معين
نماذج:
class PersonSrc( val name: String, val salary: SalarySrc ) class SalarySrc(val amount: Int) class PersonDst( val name: String, val salary: SalaryDst ) class SalaryDst(val amount: Int)
المخططون:
fun mapPerson( src: PersonSrc, salaryMapper: (SalarySrc) -> SalaryDst = ::mapSalary
في هذا المثال ، تعد mapPerson
وظيفة ترتيب أعلى منذ ذلك الحين انها تحصل على معين لنموذج Salary
. ميزة مثيرة للاهتمام في المثال المحدد هي الوسيطة الافتراضية لهذه الوظيفة. يسمح لنا هذا النهج بتبسيط رمز الاتصال وفي نفس الوقت إعادة تحديد المخطط في اختبارات الوحدة بسهولة. يمكنك استخدام طريقة التعيين هذه دون الطريقة الافتراضية ، وتمريرها دائمًا في رمز الاتصال.
إن وضع مصمم الخرائط والفئات التي يعمل بها في أماكن مختلفة من المشروع ليست ملائمة دائمًا. مع التعديل المتكرر للفصل الدراسي ، سيتعين عليك البحث عن الملفات المختلفة وتعديلها في أماكن مختلفة.
تتطلب طريقة التعيين هذه أن تكون كل الخصائص التي تحتوي على بيانات الفئة مرئية للمخطط ، أي لا يمكن استخدام الرؤية الخاصة لهم.
ملخص طريقة التعيين:
+
اختبار وحدة بسيطة
-
التعديل الصعب
-
يتطلب حقول مفتوحة لفئات البيانات
الطريقة الثالثة: وظائف الملحق
المخططون:
fun PersonSrc.toDestination( salaryMapper: (SalarySrc) -> SalaryDst = SalarySrc::toDestination ): PersonDst { return PersonDst(this.name, salaryMapper.invoke(this.salary)) } fun SalarySrc.toDestination(): SalaryDst { return SalaryDst(this.amount) }
بشكل عام ، نفس وظائف .toDestination()
، لكن بناء جملة استدعاء .toDestination()
أبسط: .toDestination()
.
تجدر الإشارة إلى أن وظائف الامتداد يمكن أن تؤدي إلى سلوك غير متوقع بسبب طبيعتها الثابتة: https://kotlinlang.org/docs/reference/extensions.html#extensions-are-resolved-statically
ملخص طريقة التعيين:
+
اختبار وحدة بسيطة
-
التعديل الصعب
-
يتطلب حقول مفتوحة لفئات البيانات
الطريقة 4: فئات معين مع واجهة
أمثلة وظيفة لها عيب. أنها تسمح لك باستخدام أي وظيفة مع توقيع (SalarySrc) -> SalaryDst
. سيساعد وجود واجهة Mapper<SRC, DST>
جعل الكود أكثر وضوحًا.
مثال:
interface Mapper<SRC, DST> { fun transform(data: SRC): DST } class PersonMapper( private val salaryMapper: Mapper<SalarySrc, SalaryDst> ) : Mapper<PersonSrc, PersonDst> { override fun transform(src: PersonSrc) = PersonDst( src.name, salaryMapper.transform(src.salary) ) } class SalaryMapper : Mapper<SalarySrc, SalaryDst> { override fun transform(src: SalarrSrc) = SalaryDst( src.amount ) }
في هذا المثال ، يعتبر PersonMapper
تبعية PersonMapper
. يسمح لك هذا باستبدال مخطط Salary
بسهولة لاختبارات الوحدة.
فيما يتعلق بالتعيين في الوظيفة ، يحتوي هذا المثال على عيب واحد فقط - الحاجة إلى كتابة رمز أكثر بقليل.
ملخص طريقة التعيين:
+
أفضل الكتابة
-
المزيد من التعليمات البرمجية
مثل وظائف معين:
+
اختبار وحدة بسيطة
-
التعديل الصعب
-
يتطلب مجالات مفتوحة لفئات البيانات
الطريقة الخامسة: الانعكاس
طريقة السحر الاسود. النظر في هذه الطريقة على نماذج أخرى.
نماذج:
data class EmployeeSrc( val firstName: String, val lastName: String, val age: Int
مخطط:
fun EmployeeSrc.mapWithRef() = with(::EmployeeDst) { val propertiesByName = EmployeeSrc::class.memberProperties.associateBy { it.name } callBy(parameters.associateWith { parameter -> when (parameter.name) { EmployeeDst::name.name -> "$firstName $lastName"
مثال تجسس هنا .
في هذا المثال ، يقوم EmployeeSrc
و EmployeeDst
بتخزين الاسم بتنسيقات مختلفة. يحتاج معين معين فقط إلى جعل اسم النموذج الجديد. تتم معالجة الحقول المتبقية تلقائيًا ، دون كتابة رمز (الخيار else
هو when
).
يمكن أن تكون الطريقة مفيدة ، على سبيل المثال ، إذا كان لديك نماذج كبيرة تحتوي على مجموعة من الحقول وتتزامن الحقول أساسًا مع النماذج نفسها من طبقات مختلفة.
ستنشأ مشكلة كبيرة ، على سبيل المثال ، إذا قمت بإضافة الحقول المطلوبة إلى Dst ولم يحدث ذلك في Src
أو في مخطط الخرائط عن طريق الصدفة: IllegalArgumentException
في وقت التشغيل. لديه انعكاس أيضا مشاكل الأداء.
ملخص طريقة التعيين:
+
رمز أقل
+
اختبار وحدة بسيطة
-
خطير
-
قد يؤثر سلبا على الأداء
النتائج
يمكن استخلاص هذه الاستنتاجات من نظرنا:
طرق معين - رمز واضح ، أسرع في الكتابة والمحافظة عليها
وظائف معين ووظائف التمديد - مجرد اختبار رسم الخرائط.
فئات معين مع واجهة - مجرد اختبار رسم الخرائط ورمز أكثر وضوحا.
انعكاس - مناسبة للحالات غير القياسية.