وراثت کلاس داده با Delegation در کاتلین – از صفر تا صد
فرض کنید پروژهای در کاتلین دارید که در آن یک کلاس Person وجود دارد. این کلاس همه مشخصههای مورد نیاز برای توصیف یک فرد شامل نام، تاریخ تولد، نشانی و غیره را دارد. ما این کلاس را به صورت یک «کلاس داده» (Data Class) درمیآوریم تا کار کردن با همه این مشخصهها آسانتر شود. با این حال با Person به عنوان یک «موجودیت» (entity) برخورد میکنیم، یعنی یک Person به خاطر Person بودنش به یک شناسه متمایز انتساب مییابد. بدین ترتیب مشکلی پیش میآید و آن این است که وقتی Person هنوز Person نشده است، یعنی پیش از آن که شناسهای به آن انتساب دهیم، چه طور میتوانیم با آن کار کنیم؟ در این مقاله راهحل این مسئله از طریق Delegation در کاتلین توضیح داده میشود.
id-های تهیپذیر
Person در مراحل ابتدایی راهاندازی یک id تهیپذیر دارد:
1data class Person(
2 val fName: String,
3 val lName: String,
4 val dob: LocalDate,
5 // ...
6 val id: UUID? = null
7)
چنان که میبینید ما یک id تهیپذیر (nullable) تعیین کردهایم. بدین ترتیب متغیری را وهلهسازی میکنیم، آن را در اختیار سیستم قرار میدهیم و سپس متغیری با id تعیینشده دریافت میکنیم.
فرض کنید توسعهدهنده دیگری یک مشخصه تهیپذیر را میبیند، بیدرنگ مشخصه را پاک میکند، نام کلاس را به PersonInfo تغییر میدهد و یک کلاس Person جدید با همان فیلدها که به صورت دستی کپی شدهاند، به علاوه بر id غیر تهیپذیر میسازد:
1data class PersonInfo(
2 val fName: String,
3 val lName: String,
4 val dob: LocalDate,
5 // ...
6)
7data class Person(
8 val fName: String,
9 val lName: String,
10 val dob: LocalDate,
11 // ...
12 val id: UUID
13)
سپس متدهای سهولت تبدیل اضافه شدهاند. این تنها روشی است که میتوان برای دیدن کلاس Person بدون id استفاده کرد. این رویکرد قابل درک است، اما وارد کردن اشیای انتقال داده که تا این حد به قلب سیستم نزدیک هستند، منجر به لایهبندی سیستمی تبدیلها میشود و هر لایهای که اضافه شود بر پیچیدگی و ناپایداری کلی میافزاید تا این که در یک زمان، دیگر Person از روی موجودیت قابل شناسایی نیست.
سپس توسعهدهنده دیگری میآید و کلاً امکان استفاده از delegation را نخواهد داشت. بدین ترتیب به نتیجه زیر میرسیم:
1interface PersonDefinition(
2 val fName: String,
3 val lName: String,
4 val dob: LocalDate,
5 // ...
6)
7data class Person(
8 private val data: PersonInfo,
9 val id: UUID
10) : PersonDefinition by data
11data class PersonInfo(
12 override val fName: String,
13 override val lName: String,
14 override val dob: LocalDate,
15 // ...
16) : PersonDefinition
مزیتهای رویکرد نوین
کد فوق محدود به دو کلاس و یک اینترفیس است، اما مزیتهای زیر را دارد:
- یک تعریف منفرد از Person در اینترفیس وجود دارد و تغییر دادن آن در سطح کامپایلر شما را ملزم به انتشار تغییرات میکند.
- هر کس یک کلاس داده است و از این رو بُردی به دست میآوریم.
- با این که Person از PersonInfo ارثبری نمیکند، اما در مورد هر چیزی که در PersonDefinition مشارکت دارد به آن delegation میکند و از این رو همه getter-ها و setter-ها و غیره دریافت میشوند.
- نیازی به ترجمه کد نیست، چون یک Person هم اینک در یک PersonInfo وجود دارد.
- دیگر نیازی به مقادیر تهیپذیر نداریم و از این رو نیازی به بررسی تهی بودن id هم نخواهیم داشت.
شاید به نظر بیاید همه این کارها برای رها شدن از شر یک id تهیپذیر کاری بیهوده است، اما این روش مزیت خود را در زمان بزرگ شدن و افزایش پیچیدگی اپلیکیشنها نشان میدهد.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی اندروید
- آموزش مقدماتی زبان برنامه نویسی کاتلین (Kotlin) برای توسعه اندروید (Android)
- مجموعه آموزشهای برنامهنویسی
- ساخت اپلیکیشن ضبط صدا با کاتلین (Kotlin) — به زبان ساده
- برنامه نویسی اندروید با کاتلین — راهنمای شروع به کار
==
جالب بود و یکم توضیحات پیچیده بود. ولی باز ممنون از زحمتت