কোটলিনে ডেটা ক্লাস প্রসারিত করুন


176

ডেটা ক্লাসগুলি জাভার পুরানো ফ্যাশন POJO- এর প্রতিস্থাপন বলে মনে হচ্ছে। এই ক্লাসগুলি উত্তরাধিকারের অনুমতি দেবে এটি যথেষ্ট প্রত্যাশাজনক, তবে আমি কোনও ডেটা বর্গ বাড়ানোর কোনও সুবিধাজনক উপায় দেখতে পাচ্ছি না। আমার যা দরকার তা হ'ল এরকম কিছু:

open data class Resource (var id: Long = 0, var location: String = "")
data class Book (var isbn: String) : Resource()

component1()পদ্ধতির সংঘাতের কারণে উপরের কোডটি ব্যর্থ । dataশুধুমাত্র একটি ক্লাসে টীকা রেখে দেওয়া কাজটি করে না।

সম্ভবত ডেটা ক্লাস প্রসারিত করার জন্য আরও একটি বুদ্ধি আছে?

ইউপিডি: আমি কেবল শিশু শিশু শ্রেণিকে dataটিকা দিতে পারি , তবে টীকাগুলি কেবল নির্মাত্রে ঘোষিত সম্পত্তিগুলি পরিচালনা করে। এটি হ'ল, আমাকে পিতামাতার সমস্ত সম্পত্তি ঘোষণা করতে হবে openএবং সেগুলি ওভাররাইড করতে হবে, যা কুৎসিত:

open class Resource (open var id: Long = 0, open var location: String = "")
data class Book (
    override var id: Long = 0,
    override var location: String = "",
    var isbn: String
) : Resource()

3
কোটলিন সুস্পষ্টভাবে এমন পদ্ধতি তৈরি করে componentN()যা N-th সম্পত্তির মান ফেরত দেয়। মাল্টি-ডিক্লারেশনে
দিমিত্রি

বৈশিষ্ট্যগুলি খোলার জন্য, আপনি রিসোর্স বিমূর্ত করতে পারেন বা সংকলক প্লাগইন ব্যবহার করতে পারেন। কোটলিন মুক্ত / বদ্ধ নীতি সম্পর্কে কঠোর।
jeljko ট্রোগ্রিলি

@ দিমিত্রি যেহেতু আমরা কোনও ডেটা ক্লাস প্রসারিত করতে পারি না, তাই অভিভাবক শ্রেণীর পরিবর্তনশীল উন্মুক্ত রাখার এবং শিশু শ্রেণিতে কেবল "ওকে" কাজ করার জন্য কী আপনার "সমাধান"?
আর্চি জি কুইনস

উত্তর:


163

সত্যটি হ'ল: ডেটা ক্লাসগুলি উত্তরাধিকারের সাথে খুব ভাল খেলে না। আমরা ডেটা ক্লাসের উত্তরাধিকার নিষিদ্ধ বা গুরুতরভাবে সীমাবদ্ধ করার বিষয়ে বিবেচনা করছি। উদাহরণস্বরূপ, এটি জানা যায় যে equals()নন-অ্যাবস্ট্রাক্ট শ্রেণিতে শ্রেণিবদ্ধভাবে সঠিকভাবে প্রয়োগ করার কোনও উপায় নেই ।

সুতরাং, আমি যা অফার করতে পারি সেগুলি: ডেটা ক্লাসের সাথে উত্তরাধিকার ব্যবহার করবেন না।


আরে আন্দ্রে, ডেটা ক্লাসে তৈরি হওয়া সমান () কীভাবে কাজ করে এখন? টাইপটি সঠিক এবং সমস্ত সাধারণ ক্ষেত্র সমান হলে বা ক্ষেত্রগুলি সমান হলেই কি এটি মেলে? দেখে মনে হচ্ছে, বীজগণিত উপাত্তের ধরণের অনুমানের জন্য শ্রেণীর উত্তরাধিকারের মানটির কারণে, এই সমস্যার সমাধানের জন্য এটি মূল্যবান হতে পারে। মজার বিষয় হচ্ছে, মার্টিন ওডারস্কির
orospakr

3
আমি বিশ্বাস করি না যে এই সমস্যার সমাধানের অনেক কিছুই আছে। আমার মতামত এ পর্যন্ত যে ডেটা ক্লাসে অবশ্যই ডেটা-সাবক্লাস থাকা উচিত নয়।
আন্দ্রে ব্রেস্লাভ

3
যদি আমাদের কাছে কোনও ওআরএম এর মতো লাইব্রেরি কোড থাকে এবং আমরা আমাদের ধ্রুবক ডেটা মডেল রাখতে এর মডেলটি প্রসারিত করতে চাই?
কৃপাল শাহ 12'15

3
ডেটা ক্লাসে অ্যান্ড্রেব্রেস্লাভ ডকস কোটলিন ১.১-এর পরে রাষ্ট্রকে প্রতিফলিত করে না। ১.১ থেকে ডেটা ক্লাস এবং উত্তরাধিকার কীভাবে একসাথে খেলবে?
ইউজেন পেচানেক

2
@ ইউজেনপ্যাচেনেক এই উদাহরণটি দেখুন: কোটলিংলং.আর্গ
অ্যান্ড্রে ব্রেস্লাভ

114

নির্মাতার বাইরে সুপার-ক্লাসের বৈশিষ্ট্যগুলি বিমূর্ত হিসাবে ঘোষণা করুন এবং সেগুলি উপ-শ্রেণিতে ওভাররাইড করুন।

abstract class Resource {
    abstract var id: Long
    abstract var location: String
}

data class Book (
    override var id: Long = 0,
    override var location: String = "",
    var isbn: String
) : Resource()

15
এটি সবচেয়ে নমনীয় বলে মনে হয়। আমি প্রি়ভাবে চাও আমরা শুধু তথ্য শ্রেণীর একে অপরের যদিও থেকে উত্তরাধিকারী হতে পারে ...
আদম

হ্যালো স্যার, ডেটা ক্লাস উত্তরাধিকার পরিচালনা করার ঝরঝরে উপায়ের জন্য ধন্যবাদ। আমি যখন জেনেরিক টাইপ হিসাবে বিমূর্ত শ্রেণিটি ব্যবহার করি তখন আমি একটি সমস্যার মুখোমুখি হয়েছি। আমি একটি Type Mismatchত্রুটি পেয়েছি: "প্রয়োজনীয় টি, পাওয়া গেছে: রিসোর্স"। জেনারিকসে কীভাবে এটি ব্যবহার করা যেতে পারে দয়া করে আমাকে বলতে পারেন?
আশ্বিন মহাজন

আমি জানতেও চাই যে জেনারিকগুলি বিমূর্ত ক্লাস জুড়ে সম্ভব কিনা। উদাহরণস্বরূপ, যদি অবস্থানটি একটি উত্তরাধিকার সূত্রে প্রাপ্ত ডেটা ক্লাস এবং একটি কাস্টম শ্রেণিতে স্ট্রিং হয় ( Location(long: Double, lat: Double))অন্যটিতে বলা যাক ?
রবি ক্রোনিন

2
আমি প্রায় আমার আশা হারিয়েছি। ধন্যবাদ!
মিখা পোভোওকা

প্যারামিটারগুলি অনুলিপি করা উত্তরাধিকার প্রয়োগের একটি খারাপ উপায় বলে মনে হচ্ছে। প্রযুক্তিগতভাবে, যেহেতু বইটি রিসোর্স থেকে উত্তরাধিকার সূত্রে প্রাপ্ত, তাই এটি আইডি এবং অবস্থানের উপস্থিতিটি জেনে রাখা উচিত। সেগুলি নির্দিষ্ট করার দরকার নেই।
অ্যান্ড্রয়েডদেভ

23

বিমূর্ত শ্রেণীর ব্যবহারের উপরের সমাধানটি প্রকৃতপক্ষে সম্পর্কিত বর্গ তৈরি করে এবং এর থেকে ডেটা শ্রেণি প্রসারিত হোক।

আপনি যদি বিমূর্ত ক্লাসটিকে পছন্দ করেন না, তবে ইন্টারফেসটি কীভাবে ব্যবহার করবেন ?

এই নিবন্ধে প্রদর্শিত কোটলিনের ইন্টারফেসের বৈশিষ্ট্য থাকতে পারে ..

interface History {
    val date: LocalDateTime
    val name: String
    val value: Int
}

data class FixedHistory(override val date: LocalDateTime,
                        override val name: String,
                        override val value: Int,
                        val fixedEvent: String) : History

আমি কৌতূহলী ছিলাম কীভাবে কোটলিন এটি সংকলন করে। এখানে সমতুল্য জাভা কোড (ইন্টেলিজ [কোটলিন বাইটকোড] বৈশিষ্ট্য ব্যবহার করে উত্পন্ন):

public interface History {
   @NotNull
   LocalDateTime getDate();

   @NotNull
   String getName();

   int getValue();
}

public final class FixedHistory implements History {
   @NotNull
   private final LocalDateTime date;
   @NotNull
   private final String name;
   private int value;
   @NotNull
   private final String fixedEvent;

   // Boring getters/setters as usual..
   // copy(), toString(), equals(), hashCode(), ...
}

আপনি দেখতে পাচ্ছেন, এটি ঠিক একটি সাধারণ ডেটা ক্লাসের মতো কাজ করে!


3
দুর্ভাগ্যক্রমে কোনও ডেটা শ্রেণীর জন্য ইন্টারফেস প্যাটার্ন প্রয়োগ করা রুমের আর্কিটেকচারের সাথে কাজ করে না।
অ্যাডাম হুরউইটজ

@ অ্যাডামহুরউইটজ এটি খুব খারাপ .. আমি তা খেয়াল করি নি!
তুরা

4

@ Željko Trogrlić উত্তরটি সঠিক। তবে আমাদের বিমূর্ত শ্রেণীর মতো একই ক্ষেত্রগুলি পুনরাবৃত্তি করতে হবে।

এছাড়াও যদি আমাদের বিমূর্ত শ্রেণীর ভিতরে বিমূর্ত সাবক্লাস থাকে তবে একটি ডেটা ক্লাসে আমরা এই বিমূর্ত সাবক্লাসগুলি থেকে ক্ষেত্রগুলি প্রসারিত করতে পারি না। আমাদের প্রথমে ডেটা সাবক্লাস তৈরি করা উচিত এবং তারপরে ক্ষেত্রগুলি সংজ্ঞায়িত করা উচিত ।

abstract class AbstractClass {
    abstract val code: Int
    abstract val url: String?
    abstract val errors: Errors?

    abstract class Errors {
        abstract val messages: List<String>?
    }
}



data class History(
    val data: String?,

    override val code: Int,
    override val url: String?,
    // Do not extend from AbstractClass.Errors here, but Kotlin allows it.
    override val errors: Errors?
) : AbstractClass() {

    // Extend a data class here, then you can use it for 'errors' field.
    data class Errors(
        override val messages: List<String>?
    ) : AbstractClass.Errors()
}

আমরা ইতিহাস সরিয়ে নিতে পারি। অ্যাবস্ট্রাকশ্লাসে ত্রুটিগুলি.আরফার্স.কম্পিয়ন.সম্প্লেআরিয়ারস বা বাইরে এবং ডেটা ক্লাসে এটি প্রতিটি উত্তরাধিকার সূত্রে প্রাপ্ত ডাটা ক্লাসে নকল করার চেয়ে ব্যবহার করতে পারি?
TWiStErRob

@TWiStErRob, এমন একজন বিখ্যাত ব্যক্তি শুনে খুশি! আমার অর্থ হিস্টিও.অর্ডারগুলি প্রতিটি ক্লাসে পরিবর্তিত হতে পারে, যাতে আমাদের এটিকে ওভাররাইড করা উচিত (উদাহরণস্বরূপ, ক্ষেত্রগুলি যুক্ত করুন)।
শীতলমাইন্ড

4

কোটলিন বৈশিষ্ট্যগুলি সাহায্য করতে পারে।

interface IBase {
    val prop:String
}

interface IDerived : IBase {
    val derived_prop:String
}

ডেটা ক্লাস

data class Base(override val prop:String) : IBase

data class Derived(override val derived_prop:String,
                   private val base:IBase) :  IDerived, IBase by base

নমুনা ব্যবহার

val b = Base("base")
val d = Derived("derived", b)

print(d.prop) //prints "base", accessing base class property
print(d.derived_prop) //prints "derived"

এই দৃষ্টিভঙ্গি @ পার্সেলাইজ সহ উত্তরাধিকার সংক্রান্ত সমস্যাগুলির জন্যও একযোগে কাজ হতে পারে

@Parcelize 
data class Base(override val prop:Any) : IBase, Parcelable

@Parcelize // works fine
data class Derived(override val derived_prop:Any,
                   private val base:IBase) : IBase by base, IDerived, Parcelable

2

আপনি অ-ডেটা ক্লাস থেকে ডেটা ক্লাস উত্তরাধিকারী হতে পারেন। অন্য ডেটা ক্লাস থেকে ডেটা ক্লাসের উত্তরাধিকার অনুমোদিত নয় কারণ উত্তরাধিকারের ক্ষেত্রে সংকলক-উত্পন্ন ডেটা ক্লাসের পদ্ধতিগুলি ধারাবাহিকভাবে এবং স্বজ্ঞাতভাবে কাজ করার কোনও উপায় নেই।


1

যদিও বাস্তবায়নে equals()একটি অনুক্রমের মধ্যে সঠিকভাবে প্রকৃতপক্ষে বেশ জরান, এটা এখনও চমৎকার উদাহরণস্বরূপ অন্যান্য পদ্ধতি inheriting সমর্থন করতে হবে: toString()

আরও কিছুটা কংক্রিট হওয়ার জন্য, ধরে নিই যে আমাদের নীচের নির্মাণগুলি রয়েছে (স্পষ্টতই, toString()উত্তরাধিকারসূত্রে প্রাপ্ত না বলে এটি কাজ করে না , তবে এটি যদি ভাল হয় না তবে কি?):

abstract class ResourceId(open val basePath: BasePath, open val id: Id) {

    // non of the subtypes inherit this... unfortunately...
    override fun toString(): String = "/${basePath.value}/${id.value}"
}
data class UserResourceId(override val id: UserId) : ResourceId(UserBasePath, id)
data class LocationResourceId(override val id: LocationId) : ResourceId(LocationBasePath, id)

ধরে নেওয়া যাক আমাদের Userএবং Locationসত্ত্বা তাদের উপযুক্ত সংস্থান আইডি (আগমন UserResourceIdএবং LocationResourceIdযথাক্রমে) কলিং toString()কোনো ResourceIdবেশ একটি চমৎকার সামান্য উপস্থাপনা থেকে পুরোপুরি অন্য সব উপশাখাকে জন্য বৈধ হতে পারে: /users/4587, /locations/23ইত্যাদি দুর্ভাগ্যবশত, কারণ উপশাখাকে অ উপেক্ষিত থেকে উত্তরাধিকারসূত্রে toString()থেকে পদ্ধতি বিমূর্ত বেস ResourceId, কলিং toString()আসলে একটি কম প্রশংসনীয় উপস্থাপনা ফলাফল: <UserResourceId(id=UserId(value=4587))>,<LocationResourceId(id=LocationId(value=23))>

উপরোক্ত মডেল করার অন্যান্য উপায় আছে, তবে সেই উপায়গুলি হয় আমাদের নন-ডেটা-ক্লাসগুলি ব্যবহার করতে বাধ্য করে (ডেটা ক্লাসের সুবিধাগুলি অনেকাংশে হারিয়ে যায়), বা আমরা toString()আমাদের সমস্ত ডেটা ক্লাসে প্রয়োগটি অনুলিপি / পুনরাবৃত্তি করে শেষ করি (কোন উত্তরাধিকার)।


0

আপনি অ-ডেটা ক্লাস থেকে ডেটা ক্লাস উত্তরাধিকারী হতে পারেন।

বেস ক্লাস

open class BaseEntity (

@ColumnInfo(name = "name") var name: String? = null,
@ColumnInfo(name = "description") var description: String? = null,
// ...
)

শিশু শ্রেণি

@Entity(tableName = "items", indices = [Index(value = ["item_id"])])
data class CustomEntity(

    @PrimaryKey
    @ColumnInfo(name = "id") var id: Long? = null,
    @ColumnInfo(name = "item_id") var itemId: Long = 0,
    @ColumnInfo(name = "item_color") var color: Int? = null

) : BaseEntity()

এটা কাজ করেছে.


এটি বাদ দিয়ে এখন আপনি নাম এবং বিবরণী বৈশিষ্ট্য সেট করতে পারবেন না, এবং আপনি যদি এগুলি নির্মাণকারীর সাথে যুক্ত করেন তবে ডেটা ক্লাসের জন্য ভাল / var প্রয়োজন যা বেস ক্লাসের বৈশিষ্ট্যগুলিকে ওভাররাইড করে।
ব্রিল পাপ্পিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.