تصنيف بيانات كوتلن

في هذا البرنامج التعليمي، سنلقي نظرة على فئة بيانات Kotlin. إذا لم تقرأ فصل فئات Kotlin، فإننا نوصيك بالقيام بذلك قبل المتابعة.

فئة بيانات Kotlin

هل تشعر بالملل من كتابة آلاف الأسطر من الشيفرة لفئات البيانات POJO في Java؟ يجب أن يكون كل مبرمج Java قد لاحظ في مرحلة ما عدد الأسطر التي يحتاجون إلى كتابتها لفئات تحتاج فقط إلى تخزين بعض البيانات. دعونا نرى كيف تبدو فئة POJO Book.java:

public class Book {

    private String name;
    private String authorName;
    private long lastModifiedTimeStamp;
    private float rating;
    private int downloads;


    public Book(String name, String authorName, long lastModified, float rating, int downloads) {
        this.name = name;
        this.authorName = authorName;
        this.lastModifiedTimeStamp = lastModified;
        this.rating = rating;
        this.downloads = downloads;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public long getLastModifiedTimeStamp() {
        return lastModifiedTimeStamp;
    }

    public void setLastModifiedTimeStamp(long lastModifiedTimeStamp) {
        this.lastModifiedTimeStamp = lastModifiedTimeStamp;
    }

    public float getRating() {
        return rating;
    }

    public void setRating(float rating) {
        this.rating = rating;
    }

    public int getDownloads() {
        return downloads;
    }

    public void setDownloads(int downloads) {
        this.downloads = downloads;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Book that = (Book) o;

        if (downloads != that.downloads)
            return false;
        if (name != null ? !name.equals(that.name) :
                that.name != null) {
            return false;
        }
        return authorName != null ?
                authorName.equals(that.authorName) :
                that.authorName == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (authorName != null ?
                authorName.hashCode() : 0);
        result = 31 * result + downloads;
        return result;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + authorName + '\'' +
                ", lastModifiedTimestamp='" + lastModifiedTimeStamp + '\'' +
                ", rating='" + rating + '\'' +
                ", downloads=" + downloads +
                '}';
    }
}

واو! هذا 96 سطرًا من الشيفرة لتخزين مجرد 5 حقول في كائن. لا نقوم بكتابة الكثير هنا إلا أننا نقوم بإنشاء getters و setters و toString() و equals() و hashCode() methods. مع الممارسات المعمارية النظيفة وفصل ممارسات الشيفرة في مشروعنا، نحتاج إلى إنشاء فئات POJO لأن كل مشروع يحتاج إلى تخزين البيانات في مكان ما. يمكن أن يزيد ذلك من الشيفرة الزائدة. هنا يأتي Kotlin للإنقاذ، باستخدام فئات البيانات. فئات البيانات هي إجابة Kotlin على تقليل الشيفرة الزائدة. يمكن كتابة الفئة POJO أعلاه في Kotlin على النحو التالي:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

هذا كل شيء. يحول Kotlin شيفرة Java تحتوي على 96 سطرًا إلى سطر واحد فقط.هذه هي طريقة Kotlin لتقليل الشيفرة الزائدة في مشروعك!

إنشاء فئة بيانات Kotlin

فيما يلي المتطلبات لإنشاء فئة بيانات Kotlin.

  • يجب عليك إضافة الكلمة المفتاحية data إلى الفئة
  • يجب أن يحتوي المُنشئ الأساسي على معامل واحد على الأقل
  • يجب أن يحتوي كل معامل في المُنشئ الأساسي على val أو var مُعين. هذا ليس الحال في الفئة العادية، حيث أن تحديد val أو var ليس إلزاميًا.
  • لا يمكن إضافة abstract، open، sealed أو inner لفئات البيانات

الطرق المُدمجة في فئة بيانات Kotlin

تنشئ فئة البيانات Kotlin تلقائيًا الدوال التالية لك.

  • equals() و hashCode()
  • toString() بشكل "Book(name=JournalDev, authorName=Anupam)"
  • الدوال componentN() لكل من المعاملات في الترتيب المحدد. وهذا معروف باسم تصريف الإعلانات
  • copy()

ميزات فئة البيانات Kotlin

فيما يلي بعض الميزات التي توفرها فئة البيانات.

  • لإنشاء مُنشئ بدون مُعاملات، حدد قيم افتراضية لكل من المُعاملات الموجودة في المُنشئ الرئيسي.

  • تسمح فئة البيانات بالتوريث (لا حاجة للإشارة بالكلمة الرئيسية open).

  • يمكنك توفير تنفيذات صريحة للدوال equals() hashCode() و toString()

  • لا يُسمح بتوفير تنفيذات صريحة للدوال copy() و componentN().

  • يمكننا التحكم في رؤية المُستقبلات والمُعاملات الضابطة عبر تحديد محدِّدات الرؤية في المُنشئ كما هو موضَّح أدناه.

    data class Book(var name: String,private var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)
    
  • لن يكون لمعامل القيمة (val) محدد للمحدث بشكل ضمني (ولا يمكن فعل ذلك بشكل صريح أيضًا!).

الوسائط الافتراضية والمسماة في فئة البيانات

فيما يلي فئتنا للبيانات:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

لم يتم تعيين قيمة افتراضية لأي من المعلمات. لذا نحتاج إلى تحديد وسيط لكل منها عند الإنشاء كما هو موضح أدناه.

fun main(args: Array<String>) {
val book = Book("Android Tutorials","Anupam", 1234567, 4.5f, 1000)
}

لنقم بتعيين بعض الوسائط الافتراضية ونرى كيف يتغير الإنشاء.


data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)
fun main(args: Array<String>) {
var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    book = Book("Kotlin")
    book = Book("Swift",downloads = 500)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    book = Book("Python","Shubham",rating = 5f)

}

بدلاً من تحديد كل وسيط ، يمكننا تعيين فقط تلك التي ليست افتراضية وتلك التي نرغب في تحديدها باستخدام وسيط الاسم. باستخدام الوسائط المسماة ، يمكننا تحديد الوسيط الخامس كالثاني عن طريق تحديد اسم المعلمة بشكل صريح تتبعه =. الحياة بهذه الطريقة أسهل بكثير!

طريقة toString() في فئة البيانات في كوتلن

تم إنشاء toString() ضمنيًا ويقوم بطباعة أسماء الوسائط وتسمياتها للحالة كما هو موضح أدناه.

data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)


fun main(args: Array) {

    var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)
    book = Book("Kotlin")
    println(book)
    book = Book("Swift",downloads = 500)
    println(book)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    println(book.toString())
    book = Book("Python","Shubham",rating = 5f)
    println(book.toString())


}

//ما يتم طباعته في واجهة التحكم.
//Book(name=دروس Android, authorName=أنوبام, lastModified=1234567, rating=4.5, downloads=1000)
//Book(name=كوتلن, authorName=أنوبام, lastModified=1234567, rating=5.0, downloads=1000)
//Book(name=سويفت, authorName=أنوبام, lastModified=1234567, rating=5.0, downloads=500)
//Book(name=جافا, authorName=بانكاج, lastModified=1234567, rating=5.0, downloads=1000)
//Book(name=بايثون, authorName=شوبهام, lastModified=1234567, rating=5.0, downloads=1000)

ملاحظة: print تقوم بإضافة دالة toString() ضمنيًا.

طريقة نسخ البيانات في كوتلن

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

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)

    val newBook = book.copy(name = "Kotlin")
    println(newBook)
}
//ما يتم طباعته في واجهة التحكم.
//Book(name=دروس Android, authorName=أنوبام, lastModified=1234567, rating=4.5, downloads=1000)
//Book(name=كوتلن, authorName=أنوبام, lastModified=1234567, rating=4.5, downloads=1000)

كوتلن Data Class equals() و hashCode()

تقوم طريقة hashCode() بإرجاع رمز التجزئة للكائن. إذا كانت كائنين متساويين، فإن hashCode() تنتج نفس نتيجة العدد الصحيح. لذا، تعيد equals() true إذا كانت قيمة hashCode() متساوية، وإلا تعيد قيمة false.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println("Hashcode is ${book.hashCode()}")

    val newBook = book.copy(name = "Kotlin")
    println("Hashcode is ${newBook.hashCode()}")

    val copyBook = book.copy()
    println("Hashcode is ${copyBook.hashCode()}")


    if(copyBook.equals(book))
        println("copyBook and book are equal")

    if(!book.equals(newBook))
        println("newBook and book are NOT equal")

}

// يتم طباعة ما يلي في وحدة التحكم.
// Hashcode هو 649213087
// Hashcode هو 1237165820
// Hashcode هو 649213087
// copyBook و book هما متساويين
// newBook و book ليستا متساويين

هشكود الكائن الأول والثالث متساويان لذا فهما متساويان. Note: طريقة equals() تعتبر مكافئة ل == في كوتلن.

تفكيك التصريحات

تسمح لنا الدالة componentN() بالوصول إلى كل من الوسيطات المحددة في البناء، بالترتيب المحدد. N هو عدد المعاملات في البناء.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    println(book.component1()) //Android tutorials
    println(book.component2()) //Anupam
    println(book.component3()) //1234567
    println(book.component4()) //4.5
    println(book.component5()) //1000
    
}

تسمح تصريحات التفكيك لنا بالوصول إلى الوسائط كخصائص من كائن الصف كما هو موضح أدناه.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book
}

ملاحظة: إذا تم تعيين محدد الرؤية مثل الخاص على أي من الوسيطات، فلا يمكن الوصول إليه في الوظيفة أعلاه.

data class Book(val name: String,private val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book //This won't compile since authorName is private
}

هذا كل شيء للمراجعة السريعة حول فصول بيانات Kotlin. المراجع: مستندات Kotlin

Source:
https://www.digitalocean.com/community/tutorials/kotlin-data-class