প্রোগ্রামারদের জন্য কোটলিন বুটক্যাম্প 4: অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং

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

ভূমিকা

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

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

আপনি ইতিমধ্যে কি জানা উচিত

  • প্রকার, অপারেটর এবং লুপিং সহ কোটলিনের মূল বিষয়গুলি৷
  • কোটলিনের ফাংশন সিনট্যাক্স
  • অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং এর মূল বিষয়
  • একটি IDE এর মৌলিক বিষয় যেমন IntelliJ IDEA বা Android Studio

আপনি কি শিখবেন

  • কোটলিনে কীভাবে ক্লাস এবং অ্যাক্সেসের বৈশিষ্ট্য তৈরি করবেন
  • কোটলিনে কীভাবে ক্লাস কনস্ট্রাক্টর তৈরি এবং ব্যবহার করবেন
  • কিভাবে একটি সাবক্লাস তৈরি করতে হয়, এবং কিভাবে উত্তরাধিকার কাজ করে
  • বিমূর্ত ক্লাস, ইন্টারফেস এবং ইন্টারফেস প্রতিনিধি সম্পর্কে
  • কিভাবে ডেটা ক্লাস তৈরি এবং ব্যবহার করতে হয়
  • সিঙ্গেলটন, এনাম এবং সিল করা ক্লাস কীভাবে ব্যবহার করবেন

আপনি কি করবেন

  • বৈশিষ্ট্য সহ একটি ক্লাস তৈরি করুন
  • একটি ক্লাসের জন্য একটি কনস্ট্রাক্টর তৈরি করুন
  • একটি সাবক্লাস তৈরি করুন
  • বিমূর্ত ক্লাস এবং ইন্টারফেসের উদাহরণ পরীক্ষা করুন
  • একটি সাধারণ ডেটা ক্লাস তৈরি করুন
  • সিঙ্গেলটন, এনাম এবং সিল করা ক্লাস সম্পর্কে জানুন

নিম্নলিখিত প্রোগ্রামিং শর্তাবলী ইতিমধ্যে আপনার পরিচিত হওয়া উচিত:

  • ক্লাস অবজেক্টের ব্লুপ্রিন্ট। উদাহরণস্বরূপ, একটি Aquarium ক্লাস একটি অ্যাকোয়ারিয়াম বস্তু তৈরির নীলনকশা।
  • অবজেক্ট হল ক্লাসের উদাহরণ; একটি অ্যাকোয়ারিয়াম বস্তু হল একটি প্রকৃত Aquarium
  • বৈশিষ্ট্য হল ক্লাসের বৈশিষ্ট্য, যেমন Aquarium দৈর্ঘ্য, প্রস্থ এবং উচ্চতা।
  • মেথড , যাকে সদস্য ফাংশনও বলা হয়, হল ক্লাসের কার্যকারিতা। পদ্ধতি হল আপনি বস্তুর সাথে "করতে পারেন"। উদাহরণস্বরূপ, আপনি একটি Aquarium বস্তু fillWithWater() করতে পারেন।
  • একটি ইন্টারফেস একটি স্পেসিফিকেশন যা একটি ক্লাস বাস্তবায়ন করতে পারে। উদাহরণস্বরূপ, অ্যাকোয়ারিয়াম ব্যতীত অন্যান্য বস্তুর জন্য পরিষ্কার করা সাধারণ, এবং পরিষ্কার করা সাধারণত বিভিন্ন বস্তুর জন্য একইভাবে ঘটে। তাই আপনার কাছে Clean নামে একটি ইন্টারফেস থাকতে পারে যা একটি clean() পদ্ধতি সংজ্ঞায়িত করে। Aquarium ক্লাস একটি নরম স্পঞ্জ দিয়ে অ্যাকোয়ারিয়াম পরিষ্কার করতে Clean ইন্টারফেস বাস্তবায়ন করতে পারে।
  • প্যাকেজগুলি সংগঠিত রাখার জন্য বা কোডের একটি লাইব্রেরি তৈরি করার জন্য সম্পর্কিত কোডগুলিকে গ্রুপ করার একটি উপায়। একবার একটি প্যাকেজ তৈরি হয়ে গেলে, আপনি প্যাকেজের বিষয়বস্তু অন্য ফাইলে আমদানি করতে পারেন এবং এতে কোড এবং ক্লাসগুলি পুনরায় ব্যবহার করতে পারেন।

এই টাস্কে, আপনি কিছু বৈশিষ্ট্য এবং একটি পদ্ধতি সহ একটি নতুন প্যাকেজ এবং একটি ক্লাস তৈরি করুন।

ধাপ 1: একটি প্যাকেজ তৈরি করুন

প্যাকেজ আপনাকে আপনার কোড সংগঠিত রাখতে সাহায্য করতে পারে।

  1. প্রকল্প ফলকে, হ্যালো কোটলিন প্রকল্পের অধীনে, src ফোল্ডারে ডান-ক্লিক করুন।
  2. নতুন > প্যাকেজ নির্বাচন করুন এবং এটিকে কল করুন example.myapp

ধাপ 2: বৈশিষ্ট্য সহ একটি ক্লাস তৈরি করুন

ক্লাস কিওয়ার্ড class দিয়ে সংজ্ঞায়িত করা হয়, এবং নিয়ম অনুসারে ক্লাসের নাম একটি বড় অক্ষর দিয়ে শুরু হয়।

  1. example.myapp প্যাকেজে ডান-ক্লিক করুন।
  2. নতুন > কোটলিন ফাইল / ক্লাস নির্বাচন করুন।
  3. কাইন্ডের অধীনে, ক্লাস নির্বাচন করুন এবং ক্লাস Aquarium নাম দিন। IntelliJ IDEA ফাইলে প্যাকেজের নাম অন্তর্ভুক্ত করে এবং আপনার জন্য একটি খালি Aquarium ক্লাস তৈরি করে।
  4. Aquarium ক্লাসের ভিতরে, প্রস্থ, উচ্চতা এবং দৈর্ঘ্যের (সেন্টিমিটারে) জন্য var বৈশিষ্ট্যগুলি সংজ্ঞায়িত করুন এবং শুরু করুন। ডিফল্ট মান সহ বৈশিষ্ট্যগুলি শুরু করুন।
package example.myapp

class Aquarium {
    var width: Int = 20
    var height: Int = 40
    var length: Int = 100
}

হুডের নিচে, কোটলিন স্বয়ংক্রিয়ভাবে Aquarium ক্লাসে আপনার সংজ্ঞায়িত বৈশিষ্ট্যগুলির জন্য গেটার এবং সেটার তৈরি করে, যাতে আপনি সরাসরি বৈশিষ্ট্যগুলি অ্যাক্সেস করতে পারেন, উদাহরণস্বরূপ, myAquarium.length

ধাপ 3: একটি main() ফাংশন তৈরি করুন

main() ফাংশন ধরে রাখতে main.kt নামে একটি নতুন ফাইল তৈরি করুন।

  1. বাম দিকে প্রজেক্ট প্যানে, example.myapp প্যাকেজে ডান-ক্লিক করুন।
  2. নতুন > কোটলিন ফাইল / ক্লাস নির্বাচন করুন।
  3. কাইন্ড ড্রপডাউনের অধীনে, নির্বাচনটিকে ফাইল হিসাবে রাখুন এবং ফাইলটির নাম দিন main.kt IntelliJ IDEA প্যাকেজের নাম অন্তর্ভুক্ত করে, কিন্তু একটি ফাইলের জন্য একটি শ্রেণীর সংজ্ঞা অন্তর্ভুক্ত করে না।
  4. একটি buildAquarium() ফাংশন সংজ্ঞায়িত করুন এবং ভিতরে Aquarium এর একটি উদাহরণ তৈরি করুন। একটি উদাহরণ তৈরি করতে, ক্লাসটি রেফারেন্স করুন যেন এটি একটি ফাংশন, Aquarium() । এটি ক্লাসের কনস্ট্রাক্টরকে কল করে এবং Aquarium ক্লাসের একটি উদাহরণ তৈরি করে, অন্যান্য ভাষায় new ব্যবহার করার মতো।
  5. একটি main() ফাংশন সংজ্ঞায়িত করুন এবং buildAquarium() কল করুন।
package example.myapp

fun buildAquarium() {
    val myAquarium = Aquarium()
}

fun main() {
    buildAquarium()
}

ধাপ 4: একটি পদ্ধতি যোগ করুন

  1. Aquarium ক্লাসে, অ্যাকোয়ারিয়ামের মাত্রা বৈশিষ্ট্যগুলি প্রিন্ট করার জন্য একটি পদ্ধতি যোগ করুন।
    fun printSize() {
        println("Width: $width cm " +
                "Length: $length cm " +
                "Height: $height cm ")
    }
  1. main.kt এ, buildAquarium() -এ, myAquarium-এ myAquarium printSize() পদ্ধতিতে কল করুন।
fun buildAquarium() {
    val myAquarium = Aquarium()
    myAquarium.printSize()
}
  1. main() ফাংশনের পাশে সবুজ ত্রিভুজ ক্লিক করে আপনার প্রোগ্রাম চালান। ফলাফল পর্যবেক্ষণ করুন।
⇒ Width: 20 cm Length: 100 cm Height: 40 cm 
  1. buildAquarium() এ, উচ্চতা 60 এ সেট করতে কোড যোগ করুন এবং পরিবর্তিত মাত্রা বৈশিষ্ট্যগুলি প্রিন্ট করুন।
fun buildAquarium() {
    val myAquarium = Aquarium()
    myAquarium.printSize()
    myAquarium.height = 60
    myAquarium.printSize()
}
  1. আপনার প্রোগ্রাম চালান এবং আউটপুট পর্যবেক্ষণ.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm 
Width: 20 cm Length: 100 cm Height: 60 cm 

এই টাস্কে, আপনি ক্লাসের জন্য একটি কনস্ট্রাক্টর তৈরি করুন এবং বৈশিষ্ট্যগুলির সাথে কাজ চালিয়ে যান।

ধাপ 1: একটি কনস্ট্রাক্টর তৈরি করুন

এই ধাপে, আপনি প্রথম টাস্কে তৈরি Aquarium ক্লাসে একজন কন্সট্রাকটর যোগ করুন। আগের উদাহরণে, Aquarium প্রতিটি উদাহরণ একই মাত্রা দিয়ে তৈরি করা হয়েছে। বৈশিষ্ট্যগুলি সেট করে এটি তৈরি হয়ে গেলে আপনি মাত্রাগুলি পরিবর্তন করতে পারেন, তবে এটি শুরু করার জন্য সঠিক আকার তৈরি করা সহজ হবে।

কিছু প্রোগ্রামিং ল্যাঙ্গুয়েজে, কনস্ট্রাক্টরকে ক্লাসের মধ্যে একটি মেথড তৈরি করে সংজ্ঞায়িত করা হয় যার নাম ক্লাসের মতো। কোটলিনে, আপনি ক্লাস ডিক্লারেশনে সরাসরি কনস্ট্রাক্টরকে সংজ্ঞায়িত করেন, বন্ধনীর ভিতরে প্যারামিটারগুলি নির্দিষ্ট করে যেন ক্লাসটি একটি পদ্ধতি। কোটলিনের ফাংশনগুলির মতো, সেই পরামিতিগুলিতে ডিফল্ট মান অন্তর্ভুক্ত থাকতে পারে।

  1. আপনার আগে তৈরি করা Aquarium ক্লাসে, length , width এবং height জন্য ডিফল্ট মান সহ তিনটি কনস্ট্রাক্টর পরামিতি অন্তর্ভুক্ত করতে ক্লাসের সংজ্ঞা পরিবর্তন করুন এবং তাদের সংশ্লিষ্ট বৈশিষ্ট্যগুলিতে বরাদ্দ করুন।
class Aquarium(length: Int = 100, width: Int = 20, height: Int = 40) {
   // Dimensions in cm
   var length: Int = length
   var width: Int = width
   var height: Int = height
...
}
  1. আরও কমপ্যাক্ট Kotlin উপায় হল var বা val ব্যবহার করে প্রপার্টিগুলিকে সরাসরি কনস্ট্রাক্টরের সাথে সংজ্ঞায়িত করা, এবং Kotlin স্বয়ংক্রিয়ভাবে গেটার এবং সেটার তৈরি করে। তারপর আপনি ক্লাসের মূল অংশে সম্পত্তি সংজ্ঞা অপসারণ করতে পারেন।
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40) {
...
}
  1. যখন আপনি সেই কনস্ট্রাক্টরের সাথে একটি Aquarium অবজেক্ট তৈরি করেন, তখন আপনি কোনো আর্গুমেন্ট নির্দিষ্ট করতে পারবেন না এবং ডিফল্ট মান পেতে পারেন, অথবা শুধুমাত্র কিছু নির্দিষ্ট করতে পারেন, বা তাদের সবগুলি নির্দিষ্ট করতে পারেন এবং একটি সম্পূর্ণ কাস্টম-আকারের Aquarium তৈরি করতে পারেন৷ buildAquarium() ফাংশনে, নামযুক্ত প্যারামিটার ব্যবহার করে Aquarium অবজেক্ট তৈরি করার বিভিন্ন উপায় ব্যবহার করে দেখুন।
fun buildAquarium() {
    val aquarium1 = Aquarium()
    aquarium1.printSize()
    // default height and length
    val aquarium2 = Aquarium(width = 25)
    aquarium2.printSize()
    // default width
    val aquarium3 = Aquarium(height = 35, length = 110)
    aquarium3.printSize()
    // everything custom
    val aquarium4 = Aquarium(width = 25, height = 35, length = 110)
    aquarium4.printSize()
}
  1. প্রোগ্রামটি চালান এবং আউটপুট পর্যবেক্ষণ করুন।
⇒ Width: 20 cm Length: 100 cm Height: 40 cm 
Width: 25 cm Length: 100 cm Height: 40 cm 
Width: 20 cm Length: 110 cm Height: 35 cm 
Width: 25 cm Length: 110 cm Height: 35 cm 

লক্ষ্য করুন যে আপনাকে কনস্ট্রাক্টরকে ওভারলোড করতে হবে না এবং এই প্রতিটি ক্ষেত্রের জন্য একটি ভিন্ন সংস্করণ লিখতে হবে না (এছাড়া অন্যান্য সংমিশ্রণের জন্য আরও কয়েকটি)। Kotlin ডিফল্ট মান এবং নাম দেওয়া প্যারামিটার থেকে যা প্রয়োজন তা তৈরি করে।

ধাপ 2: init ব্লক যোগ করুন

উপরের উদাহরণ কনস্ট্রাক্টরগুলি কেবলমাত্র বৈশিষ্ট্যগুলি ঘোষণা করে এবং তাদের কাছে একটি অভিব্যক্তির মান নির্ধারণ করে। আপনার কনস্ট্রাক্টরের যদি আরও ইনিশিয়ালাইজেশন কোডের প্রয়োজন হয় তবে এটি এক বা একাধিক init ব্লকে স্থাপন করা যেতে পারে। এই ধাপে, আপনি Aquarium ক্লাসে কিছু init ব্লক যোগ করুন।

  1. Aquarium ক্লাসে, অবজেক্টটি ইনিশিয়ালাইজ করছে তা প্রিন্ট করতে একটি init ব্লক এবং লিটারে ভলিউম প্রিন্ট করার জন্য একটি দ্বিতীয় ব্লক যোগ করুন।
class Aquarium (var length: Int = 100, var width: Int = 20, var height: Int = 40) {
    init {
        println("aquarium initializing")
    }
    init {
        // 1 liter = 1000 cm^3
        println("Volume: ${width * length * height / 1000} l")
    }
}
  1. প্রোগ্রামটি চালান এবং আউটপুট পর্যবেক্ষণ করুন।
aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 40 cm 
aquarium initializing
Volume: 100 l
Width: 25 cm Length: 100 cm Height: 40 cm 
aquarium initializing
Volume: 77 l
Width: 20 cm Length: 110 cm Height: 35 cm 
aquarium initializing
Volume: 96 l
Width: 25 cm Length: 110 cm Height: 35 cm 

লক্ষ্য করুন যে init ব্লকগুলি শ্রেণী সংজ্ঞায় যে ক্রমে প্রদর্শিত হয় সেই ক্রমানুসারে নির্বাহ করা হয় এবং যখন কন্সট্রাক্টরকে ডাকা হয় তখন সেগুলির সবগুলিই সম্পাদিত হয়।

ধাপ 3: সেকেন্ডারি কনস্ট্রাক্টর সম্পর্কে জানুন

এই ধাপে, আপনি সেকেন্ডারি কনস্ট্রাক্টর সম্পর্কে শিখবেন এবং আপনার ক্লাসে একটি যোগ করুন। একটি প্রাথমিক কনস্ট্রাক্টর ছাড়াও, যার এক বা একাধিক init ব্লক থাকতে পারে, একটি Kotlin ক্লাসে এক বা একাধিক সেকেন্ডারি কনস্ট্রাক্টর থাকতে পারে যাতে কনস্ট্রাক্টর ওভারলোডিং, অর্থাৎ বিভিন্ন আর্গুমেন্ট সহ কনস্ট্রাক্টর থাকতে পারে।

  1. Aquarium ক্লাসে, constructor কীওয়ার্ড ব্যবহার করে একটি সেকেন্ডারি কনস্ট্রাক্টর যোগ করুন যেটি তার আর্গুমেন্ট হিসাবে বেশ কয়েকটি মাছ নেয়। মাছের সংখ্যার উপর ভিত্তি করে লিটারে অ্যাকোয়ারিয়ামের গণনাকৃত আয়তনের জন্য একটি ভাল val সম্পত্তি তৈরি করুন। ধরে নিন মাছের প্রতি 2 লিটার (2,000 সেমি^3) জল, আরও একটু বাড়তি ঘর যাতে জল ছিটকে না যায়৷
constructor(numberOfFish: Int) : this() {
    // 2,000 cm^3 per fish + extra room so water doesn't spill
    val tank = numberOfFish * 2000 * 1.1
}
  1. সেকেন্ডারি কনস্ট্রাক্টরের ভিতরে, দৈর্ঘ্য এবং প্রস্থ (যা প্রাথমিক কনস্ট্রাক্টরে সেট করা হয়েছিল) একই রাখুন এবং ট্যাঙ্কটিকে প্রদত্ত ভলিউম করতে প্রয়োজনীয় উচ্চতা গণনা করুন।
    // calculate the height needed
    height = (tank / (length * width)).toInt()
  1. buildAquarium() ফাংশনে, আপনার নতুন সেকেন্ডারি কনস্ট্রাক্টর ব্যবহার করে একটি Aquarium তৈরি করতে একটি কল যোগ করুন। আকার এবং ভলিউম প্রিন্ট করুন।
fun buildAquarium() {
    val aquarium6 = Aquarium(numberOfFish = 29)
    aquarium6.printSize()
    println("Volume: ${aquarium6.width * aquarium6.length * aquarium6.height / 1000} l")
}
  1. আপনার প্রোগ্রাম চালান এবং আউটপুট পর্যবেক্ষণ.
⇒ aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 31 cm 
Volume: 62 l

লক্ষ্য করুন যে ভলিউমটি দুইবার প্রিন্ট করা হয়েছে, একবার সেকেন্ডারি কনস্ট্রাক্টর কার্যকর করার আগে প্রাথমিক কনস্ট্রাক্টরের init ব্লক দ্বারা, এবং একবার buildAquarium() এর কোড দ্বারা।

আপনি প্রাথমিক কনস্ট্রাক্টরেও constructor কীওয়ার্ড অন্তর্ভুক্ত করতে পারেন, তবে বেশিরভাগ ক্ষেত্রে এটি প্রয়োজনীয় নয়।

ধাপ 4: একটি নতুন সম্পত্তি গেটার যোগ করুন

এই ধাপে, আপনি একটি স্পষ্ট সম্পত্তি গেটার যোগ করুন। আপনি যখন বৈশিষ্ট্যগুলি সংজ্ঞায়িত করেন তখন Kotlin স্বয়ংক্রিয়ভাবে গেটার এবং সেটারের সংজ্ঞা দেয়, কিন্তু কখনও কখনও একটি সম্পত্তির মান সামঞ্জস্য বা গণনা করা প্রয়োজন। উদাহরণস্বরূপ, উপরে, আপনি Aquarium ভলিউম মুদ্রণ করেছেন। আপনি এটির জন্য একটি পরিবর্তনশীল এবং একটি গেটার সংজ্ঞায়িত করে একটি সম্পত্তি হিসাবে ভলিউম উপলব্ধ করতে পারেন। যেহেতু volume গণনা করা প্রয়োজন, গেটারকে গণনা করা মান ফেরত দিতে হবে, যা আপনি একটি এক-লাইন ফাংশন দিয়ে করতে পারেন।

  1. Aquarium ক্লাসে, volume নামক একটি Int সম্পত্তি সংজ্ঞায়িত করুন এবং একটি get() পদ্ধতি সংজ্ঞায়িত করুন যা পরবর্তী লাইনে ভলিউম গণনা করে।
val volume: Int
    get() = width * height * length / 1000  // 1000 cm^3 = 1 l
  1. ভলিউম প্রিন্ট করে এমন init ব্লকটি সরান।
  2. buildAquarium() এর কোডটি সরান যা ভলিউম প্রিন্ট করে।
  3. printSize() পদ্ধতিতে, ভলিউম প্রিন্ট করতে একটি লাইন যোগ করুন।
fun printSize() {
    println("Width: $width cm " +
            "Length: $length cm " +
            "Height: $height cm "
    )
    // 1 l = 1000 cm^3
    println("Volume: $volume l")
}
  1. আপনার প্রোগ্রাম চালান এবং আউটপুট পর্যবেক্ষণ.
⇒ aquarium initializing
Width: 20 cm Length: 100 cm Height: 31 cm 
Volume: 62 l

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

ধাপ 5: একটি প্রপার্টি সেটার যোগ করুন

এই ধাপে, আপনি ভলিউমের জন্য একটি নতুন সম্পত্তি সেটার তৈরি করুন।

  1. Aquarium ক্লাসে, volume var এ পরিবর্তন করুন যাতে এটি একাধিকবার সেট করা যায়।
  2. গেটারের নিচে একটি set() পদ্ধতি যোগ করে volume প্রপার্টির জন্য একটি সেটার যোগ করুন, যা সরবরাহকৃত পানির পরিমাণের উপর ভিত্তি করে উচ্চতা পুনরায় গণনা করে। নিয়ম অনুসারে, সেটার প্যারামিটারের নাম হল value , তবে আপনি যদি চান তবে আপনি এটি পরিবর্তন করতে পারেন।
var volume: Int
    get() = width * height * length / 1000
    set(value) {
        height = (value * 1000) / (width * length)
    }
  1. buildAquarium() এ, অ্যাকোয়ারিয়ামের ভলিউম 70 লিটারে সেট করতে কোড যোগ করুন। নতুন আকার প্রিন্ট করুন।
fun buildAquarium() {
    val aquarium6 = Aquarium(numberOfFish = 29)
    aquarium6.printSize()
    aquarium6.volume = 70
    aquarium6.printSize()
}
  1. আপনার প্রোগ্রামটি আবার চালান এবং পরিবর্তিত উচ্চতা এবং ভলিউম পর্যবেক্ষণ করুন।
⇒ aquarium initialized
Width: 20 cm Length: 100 cm Height: 31 cm 
Volume: 62 l
Width: 20 cm Length: 100 cm Height: 35 cm 
Volume: 70 l

কোডটিতে এখন পর্যন্ত কোনো দৃশ্যমানতা পরিবর্তনকারী, যেমন public বা private , নেই। কারণ ডিফল্টরূপে, কোটলিনের সবকিছুই সর্বজনীন, যার মানে ক্লাস, পদ্ধতি, বৈশিষ্ট্য এবং সদস্য ভেরিয়েবল সহ সবকিছুই সর্বত্র অ্যাক্সেস করা যেতে পারে।

কোটলিনে, ক্লাস, অবজেক্ট, ইন্টারফেস, কনস্ট্রাক্টর, ফাংশন, প্রোপার্টি এবং তাদের সেটারের ভিজিবিলিটি মডিফায়ার থাকতে পারে:

  • public মানে ক্লাসের বাইরে দৃশ্যমান। ক্লাসের ভেরিয়েবল এবং পদ্ধতি সহ সবকিছুই ডিফল্টরূপে সর্বজনীন।
  • internal মানে এটি শুধুমাত্র সেই মডিউলের মধ্যে দৃশ্যমান হবে। একটি মডিউল হল কোটলিন ফাইলগুলির একটি সেট যা একসাথে সংকলিত হয়, উদাহরণস্বরূপ, একটি লাইব্রেরি বা অ্যাপ্লিকেশন।
  • private মানে এটি শুধুমাত্র সেই ক্লাসে দৃশ্যমান হবে (বা যদি আপনি ফাংশনগুলির সাথে কাজ করেন তবে উত্স ফাইল)।
  • protected private হিসাবে একই, তবে এটি যেকোন উপশ্রেণীতেও দৃশ্যমান হবে।

আরও তথ্যের জন্য কোটলিন ডকুমেন্টেশনে দৃশ্যমানতা পরিবর্তনকারী দেখুন।

সদস্য ভেরিয়েবল

একটি শ্রেণীর মধ্যে বৈশিষ্ট্য, বা সদস্য ভেরিয়েবল, ডিফল্টরূপে public । যদি আপনি তাদের var দিয়ে সংজ্ঞায়িত করেন, তারা পরিবর্তনযোগ্য, অর্থাৎ, পাঠযোগ্য এবং লেখার যোগ্য। আপনি যদি এগুলিকে val দিয়ে সংজ্ঞায়িত করেন, তবে শুরু করার পরে সেগুলি কেবল পঠনযোগ্য।

আপনি যদি এমন একটি সম্পত্তি চান যা আপনার কোড পড়তে বা লিখতে পারে, কিন্তু বাইরের কোডটি কেবল পড়তে পারে, আপনি সম্পত্তি এবং এর গেটারকে সর্বজনীন হিসাবে ছেড়ে দিতে পারেন এবং নীচে দেখানো হিসাবে সেটারকে ব্যক্তিগত ঘোষণা করতে পারেন।

var volume: Int
    get() = width * height * length / 1000
    private set(value) {
        height = (value * 1000) / (width * length)
    }

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

কোটলিনে, ডিফল্টরূপে, ক্লাসগুলি সাবক্লাস করা যাবে না। একইভাবে, বৈশিষ্ট্য এবং সদস্য ভেরিয়েবল সাবক্লাস দ্বারা ওভাররাইড করা যাবে না (যদিও সেগুলি অ্যাক্সেস করা যেতে পারে)।

আপনাকে অবশ্যই একটি ক্লাস open হিসাবে চিহ্নিত করতে হবে যাতে এটিকে সাবক্লাস করা যায়। একইভাবে, সাবক্লাসে ওভাররাইড করার জন্য আপনাকে অবশ্যই বৈশিষ্ট্য এবং সদস্য ভেরিয়েবলগুলিকে open হিসাবে চিহ্নিত করতে হবে। ক্লাসের ইন্টারফেসের অংশ হিসেবে ভুলবশত বাস্তবায়নের বিবরণ ফাঁস হওয়া রোধ করতে open কীওয়ার্ড প্রয়োজন।

ধাপ 1: অ্যাকোয়ারিয়াম ক্লাস খোলা করুন

এই ধাপে, আপনি Aquarium শ্রেণীটি open করবেন, যাতে আপনি পরবর্তী ধাপে এটিকে ওভাররাইড করতে পারেন।

  1. open কীওয়ার্ড দিয়ে Aquarium ক্লাস এবং এর সমস্ত বৈশিষ্ট্য চিহ্নিত করুন।
open class Aquarium (open var length: Int = 100, open var width: Int = 20, open var height: Int = 40) {
    open var volume: Int
        get() = width * height * length / 1000
        set(value) {
            height = (value * 1000) / (width * length)
        }
  1. "rectangle" মান সহ একটি খোলা shape বৈশিষ্ট্য যোগ করুন।
   open val shape = "rectangle"
  1. একটি গেটারের সাথে একটি খোলা water সম্পত্তি যোগ করুন যা Aquarium আয়তনের 90% ফেরত দেয়।
    open var water: Double = 0.0
        get() = volume * 0.9
  1. আকৃতি প্রিন্ট করতে printSize() পদ্ধতিতে কোড যোগ করুন এবং ভলিউমের শতাংশ হিসেবে পানির পরিমাণ।
fun printSize() {
    println(shape)
    println("Width: $width cm " +
            "Length: $length cm " +
            "Height: $height cm ")
    // 1 l = 1000 cm^3
    println("Volume: $volume l Water: $water l (${water/volume*100.0}% full)")
}
  1. buildAquarium() এ, width = 25 , length = 25 এবং height = 40 সহ একটি Aquarium তৈরি করতে কোড পরিবর্তন করুন।
fun buildAquarium() {
    val aquarium6 = Aquarium(length = 25, width = 25, height = 40)
    aquarium6.printSize()
}
  1. আপনার প্রোগ্রাম চালান এবং নতুন আউটপুট পর্যবেক্ষণ করুন.
⇒ aquarium initializing
rectangle
Width: 25 cm Length: 25 cm Height: 40 cm 
Volume: 25 l Water: 22.5 l (90.0% full)

ধাপ 2: একটি সাবক্লাস তৈরি করুন

  1. TowerTank নামে Aquarium একটি সাবক্লাস তৈরি করুন, যা একটি আয়তক্ষেত্রাকার ট্যাঙ্কের পরিবর্তে একটি গোলাকার সিলিন্ডার ট্যাঙ্ক প্রয়োগ করে। আপনি Aquarium এর নিচে TowerTank যোগ করতে পারেন, কারণ আপনি Aquarium ক্লাসের মতো একই ফাইলে আরেকটি ক্লাস যোগ করতে পারেন।
  2. TowerTank এ, height বৈশিষ্ট্যকে ওভাররাইড করুন, যা কনস্ট্রাক্টরে সংজ্ঞায়িত করা হয়েছে। একটি সম্পত্তি ওভাররাইড করতে, সাবক্লাসে override কীওয়ার্ড ব্যবহার করুন।
  1. টাওয়ারট্যাঙ্কের জন্য TowerTank একটি diameter নিন। Aquarium সুপারক্লাসে কনস্ট্রাক্টরকে কল করার সময় length এবং width উভয়ের জন্য diameter ব্যবহার করুন।
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
  1. একটি সিলিন্ডার গণনা করতে ভলিউম বৈশিষ্ট্য ওভাররাইড করুন। একটি সিলিন্ডারের সূত্র হল পাই গুণ ব্যাসার্ধের বর্গ গুণ উচ্চতা। আপনাকে java.lang.Math থেকে ধ্রুবক PI আমদানি করতে হবে।
    override var volume: Int
    // ellipse area = π * r1 * r2
    get() = (width/2 * length/2 * height / 1000 * PI).toInt()
    set(value) {
        height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
    }
  1. TowerTank , water সম্পত্তিকে ভলিউমের 80% হতে ওভাররাইড করুন।
override var water = volume * 0.8
  1. shape "cylinder" হতে ওভাররাইড করুন।
override val shape = "cylinder"
  1. আপনার চূড়ান্ত TowerTank ক্লাসটি নীচের কোডের মতো দেখতে হবে।

Aquarium.kt :

package example.myapp

import java.lang.Math.PI

... // existing Aquarium class

class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
    override var volume: Int
    // ellipse area = π * r1 * r2
    get() = (width/2 * length/2 * height / 1000 * PI).toInt()
    set(value) {
        height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
    }

    override var water = volume * 0.8
    override val shape = "cylinder"
}
  1. TowerTank buildAquarium() এ, 25 সেমি ব্যাস এবং 45 সেমি উচ্চতা সহ একটি টাওয়ার ট্যাঙ্ক তৈরি করুন। সাইজ প্রিন্ট করুন।

main.kt:

package example.myapp

fun buildAquarium() {
    val myAquarium = Aquarium(width = 25, length = 25, height = 40)
    myAquarium.printSize()
    val myTower = TowerTank(diameter = 25, height = 40)
    myTower.printSize()
}
  1. আপনার প্রোগ্রাম চালান এবং আউটপুট পর্যবেক্ষণ.
⇒ aquarium initializing
rectangle
Width: 25 cm Length: 25 cm Height: 40 cm 
Volume: 25 l Water: 22.5 l (90.0% full)
aquarium initializing
cylinder
Width: 25 cm Length: 25 cm Height: 40 cm 
Volume: 18 l Water: 14.4 l (80.0% full)

কখনও কখনও আপনি কিছু সম্পর্কিত শ্রেণীর মধ্যে ভাগ করা সাধারণ আচরণ বা বৈশিষ্ট্য সংজ্ঞায়িত করতে চান। কোটলিন এটি করার দুটি উপায় অফার করে, ইন্টারফেস এবং বিমূর্ত ক্লাস। এই কাজটিতে, আপনি সমস্ত মাছের জন্য সাধারণ বৈশিষ্ট্যগুলির জন্য একটি বিমূর্ত AquariumFish ফিশ ক্লাস তৈরি করুন। সমস্ত মাছের সাধারণ আচরণকে সংজ্ঞায়িত করতে আপনি FishAction নামে একটি ইন্টারফেস তৈরি করেন।

  • একটি বিমূর্ত শ্রেণী বা একটি ইন্টারফেস নিজে থেকে তাত্ক্ষণিক করা যাবে না, যার মানে আপনি সরাসরি এই ধরনের বস্তু তৈরি করতে পারবেন না।
  • বিমূর্ত ক্লাসের কনস্ট্রাক্টর আছে।
  • ইন্টারফেসে কোনো কনস্ট্রাক্টর লজিক থাকতে পারে না বা কোনো স্টেট স্টোর করতে পারে না।

ধাপ 1. একটি বিমূর্ত ক্লাস তৈরি করুন

  1. example.myapp এর অধীনে, একটি নতুন ফাইল তৈরি করুন, AquariumFish.kt
  2. AquariumFish নামেও একটি ক্লাস তৈরি করুন এবং এটিকে abstract দিয়ে চিহ্নিত করুন।
  3. একটি String বৈশিষ্ট্য, color যোগ করুন এবং abstract দিয়ে চিহ্নিত করুন।
package example.myapp

abstract class AquariumFish {
    abstract val color: String
}
  1. AquariumFish ফিশ, Shark এবং Plecostomus দুটি উপশ্রেণী তৈরি করুন।
  2. যেহেতু color বিমূর্ত, সাবক্লাসগুলি অবশ্যই এটি বাস্তবায়ন করবে। Shark ধূসর এবং Plecostomus সোনার করুন।
class Shark: AquariumFish() {
    override val color = "gray"
}

class Plecostomus: AquariumFish() {
    override val color = "gold"
}
  1. main.kt- এ, আপনার ক্লাস পরীক্ষা করার জন্য একটি makeFish() ফাংশন তৈরি করুন। একটি Shark এবং একটি Plecostomus ইনস্ট্যান্ট করুন, তারপর প্রতিটির রঙ মুদ্রণ করুন।
  2. main() এ আপনার আগের পরীক্ষার কোড মুছে দিন এবং makeFish() একটি কল যোগ করুন। আপনার কোড নীচের কোড মত কিছু দেখতে হবে.

main.kt :

package example.myapp

fun makeFish() {
    val shark = Shark()
    val pleco = Plecostomus()

    println("Shark: ${shark.color}")
    println("Plecostomus: ${pleco.color}")
}

fun main () {
    makeFish()
}
  1. আপনার প্রোগ্রাম চালান এবং আউটপুট পর্যবেক্ষণ.
⇒ Shark: gray 
Plecostomus: gold

নিম্নলিখিত চিত্রটি Shark শ্রেণী এবং Plecostomus শ্রেণীর প্রতিনিধিত্ব করে, যা বিমূর্ত শ্রেণী, AquariumFish ফিশকে উপশ্রেণী করে।

A diagram showing the abstract class, AquariumFish, and two subclasses, Shark and Plecostumus.

ধাপ 2. একটি ইন্টারফেস তৈরি করুন

  1. AquariumFish.kt- এ, eat() মেথড দিয়ে FishAction নামে একটি ইন্টারফেস তৈরি করুন।
interface FishAction  {
    fun eat()
}
  1. প্রতিটি সাবক্লাসে FishAction যোগ করুন, এবং মাছ যা করে তা প্রিন্ট করে eat() প্রয়োগ করুন।
class Shark: AquariumFish(), FishAction {
    override val color = "gray"
    override fun eat() {
        println("hunt and eat fish")
    }
}

class Plecostomus: AquariumFish(), FishAction {
    override val color = "gold"
    override fun eat() {
        println("eat algae")
    }
}
  1. makeFish() ফাংশনে, আপনার তৈরি করা প্রতিটি মাছকে eat() বলে কিছু খেতে বলুন।
fun makeFish() {
    val shark = Shark()
    val pleco = Plecostomus()
    println("Shark: ${shark.color}")
    shark.eat()
    println("Plecostomus: ${pleco.color}")
    pleco.eat()
}
  1. আপনার প্রোগ্রাম চালান এবং আউটপুট পর্যবেক্ষণ.
⇒ Shark: gray
hunt and eat fish
Plecostomus: gold
eat algae

নিম্নলিখিত চিত্রটি Shark শ্রেণী এবং Plecostomus শ্রেণীর প্রতিনিধিত্ব করে, উভয়ই FishAction ইন্টারফেসের সমন্বয়ে গঠিত এবং বাস্তবায়ন করে।

কখন বিমূর্ত ক্লাস বনাম ইন্টারফেস ব্যবহার করবেন

উপরের উদাহরণগুলি সহজ, কিন্তু যখন আপনার অনেকগুলি আন্তঃসম্পর্কিত ক্লাস থাকে, তখন বিমূর্ত ক্লাস এবং ইন্টারফেসগুলি আপনাকে আপনার ডিজাইনকে আরও পরিষ্কার, আরও সংগঠিত এবং বজায় রাখা সহজ রাখতে সাহায্য করতে পারে।

উপরে উল্লিখিত হিসাবে, বিমূর্ত ক্লাসে কনস্ট্রাক্টর থাকতে পারে, এবং ইন্টারফেস হতে পারে না, তবে অন্যথায় তারা খুব অনুরূপ। সুতরাং, আপনি যখন প্রতিটি ব্যবহার করা উচিত?

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

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

  • একটি ইন্টারফেস ব্যবহার করুন যদি আপনার অনেকগুলি পদ্ধতি এবং এক বা দুটি ডিফল্ট বাস্তবায়ন থাকে, উদাহরণস্বরূপ নীচের AquariumAction এর মতো।
interface AquariumAction {
    fun eat()
    fun jump()
    fun clean()
    fun catchFish()
    fun swim()  {
        println("swim")
    }
}
  • যে কোনো সময় আপনি একটি ক্লাস সম্পূর্ণ করতে না পারলে একটি বিমূর্ত ক্লাস ব্যবহার করুন। উদাহরণস্বরূপ, AquariumFish ক্লাসে ফিরে গিয়ে, আপনি সমস্ত AquariumFish FishAction প্রয়োগ করতে পারেন, এবং color বিমূর্ত রেখে eat জন্য একটি ডিফল্ট বাস্তবায়ন প্রদান করতে পারেন, কারণ মাছের জন্য আসলেই কোনো ডিফল্ট রঙ নেই।
interface FishAction  {
    fun eat()
}

abstract class AquariumFish: FishAction {
   abstract val color: String
   override fun eat() = println("yum")
}

পূর্ববর্তী কাজটি বিমূর্ত ক্লাস, ইন্টারফেস এবং রচনার ধারণা চালু করেছিল। ইন্টারফেস অর্পণ একটি উন্নত কৌশল যেখানে একটি ইন্টারফেসের পদ্ধতিগুলি একটি সাহায্যকারী (বা প্রতিনিধি) অবজেক্ট দ্বারা প্রয়োগ করা হয়, যা একটি শ্রেণী দ্বারা ব্যবহৃত হয়। এই কৌশলটি উপযোগী হতে পারে যখন আপনি একটি সম্পর্কহীন ক্লাসের একটি সিরিজে একটি ইন্টারফেস ব্যবহার করেন: আপনি একটি পৃথক হেল্পার ক্লাসে প্রয়োজনীয় ইন্টারফেস কার্যকারিতা যোগ করেন এবং প্রতিটি ক্লাস কার্যকারিতা বাস্তবায়নের জন্য সহায়ক শ্রেণীর একটি উদাহরণ ব্যবহার করে।

এই টাস্কে, আপনি একটি ক্লাসে কার্যকারিতা যোগ করতে ইন্টারফেস প্রতিনিধিত্ব ব্যবহার করেন।

ধাপ 1: একটি নতুন ইন্টারফেস তৈরি করুন

  1. AquariumFish.kt- এ, AquariumFish ক্লাসটি সরিয়ে দিন। AquariumFish ক্লাস থেকে উত্তরাধিকারী হওয়ার পরিবর্তে, Plecostomus এবং Shark মাছের ক্রিয়া এবং তাদের রঙ উভয়ের জন্য ইন্টারফেস প্রয়োগ করতে যাচ্ছে।
  2. একটি নতুন ইন্টারফেস তৈরি করুন, FishColor , যা রঙটিকে একটি স্ট্রিং হিসাবে সংজ্ঞায়িত করে।
interface FishColor {
    val color: String
}
  1. দুটি ইন্টারফেস, FishAction , এবং একটি FishColor বাস্তবায়ন করতে Plecostomus পরিবর্তন করুন। আপনাকে FishColor থেকে color ওভাররাইড করতে হবে এবং FishColor থেকে eat() FishAction
class Plecostomus: FishAction, FishColor {
    override val color = "gold"
    override fun eat() {
        println("eat algae")
    }
}
  1. AquariumFish থেকে উত্তরাধিকারী হওয়ার পরিবর্তে FishAction এবং FishColor , দুটি ইন্টারফেস বাস্তবায়ন করতে আপনার Shark ক্লাস পরিবর্তন করুন।
class Shark: FishAction, FishColor {
    override val color = "gray"
    override fun eat() {
        println("hunt and eat fish")
    }
}
  1. আপনার সমাপ্ত কোড এই মত কিছু দেখতে হবে:
package example.myapp

interface FishAction {
    fun eat()
}

interface FishColor {
    val color: String
}

class Plecostomus: FishAction, FishColor {
    override val color = "gold"
    override fun eat() {
        println("eat algae")
    }
}

class Shark: FishAction, FishColor {
    override val color = "gray"
    override fun eat() {
        println("hunt and eat fish")
    }
}

ধাপ 2: একটি সিঙ্গলটন ক্লাস তৈরি করুন

এরপরে, আপনি একটি সহায়ক শ্রেণী তৈরি করে প্রতিনিধি অংশের জন্য সেটআপ বাস্তবায়ন করেন যা FishColor প্রয়োগ করে। আপনি FishColor নামে একটি বেসিক ক্লাস তৈরি করুন যা GoldColor প্রয়োগ করে—এটি শুধু বলে যে এর রঙ সোনার।

GoldColor এর একাধিক দৃষ্টান্ত তৈরি করার কোনো মানে হয় না, কারণ তারা সবাই ঠিক একই কাজ করবে। সুতরাং কোটলিন আপনাকে একটি ক্লাস ঘোষণা করতে দেয় যেখানে আপনি class পরিবর্তে কীওয়ার্ড object ব্যবহার করে শুধুমাত্র একটি উদাহরণ তৈরি করতে পারেন। কোটলিন সেই একটি দৃষ্টান্ত তৈরি করবে, এবং সেই দৃষ্টান্তটি শ্রেণির নাম দ্বারা উল্লেখ করা হয়েছে। তারপর অন্যান্য সমস্ত বস্তু শুধুমাত্র এই একটি উদাহরণ ব্যবহার করতে পারে - এই শ্রেণীর অন্যান্য উদাহরণ তৈরি করার কোন উপায় নেই। আপনি যদি সিঙ্গেলটন প্যাটার্নের সাথে পরিচিত হন, তাহলে আপনি কোটলিনে সিঙ্গেলটনকে এইভাবে প্রয়োগ করবেন।

  1. AquariumFish.kt- এ, GoldColor এর জন্য একটি বস্তু তৈরি করুন। রঙ ওভাররাইড করুন।
object GoldColor : FishColor {
   override val color = "gold"
}

ধাপ 3: FishColor এর জন্য ইন্টারফেস প্রতিনিধি যোগ করুন

এখন আপনি ইন্টারফেস প্রতিনিধি ব্যবহার করার জন্য প্রস্তুত।

  1. AquariumFish.kt- এ, Plecostomus থেকে color ওভাররাইড সরিয়ে দিন।
  2. GoldColor কালার থেকে এর রঙ পেতে Plecostomus ক্লাস পরিবর্তন করুন। আপনি বর্গ ঘোষণায় by GoldColor , প্রতিনিধি তৈরি করে এটি করেন। এটি যা বলে তা হল FishColor বাস্তবায়নের পরিবর্তে, FishColor দ্বারা GoldColor বাস্তবায়ন ব্যবহার করুন। তাই প্রতিবার color অ্যাক্সেস করা হলে, এটি GoldColor এ অর্পণ করা হয়।
class Plecostomus:  FishAction, FishColor by GoldColor {
   override fun eat() {
       println("eat algae")
   }
}

ক্লাসের সাথে সাথে, সমস্ত প্লেকো সোনালি হবে, তবে এই মাছগুলি আসলে অনেক রঙে আসে। আপনি Plecostomus-এর জন্য ডিফল্ট রঙ হিসাবে GoldColor এর সাথে রঙের জন্য একটি কনস্ট্রাক্টর প্যারামিটার যোগ করে Plecostomus করতে পারেন।

  1. Plecostomus ক্লাস পরিবর্তন করুন fishColor সাথে পাস করতে এবং এটির ডিফল্ট সেট করুন GoldColor । প্রতিনিধিদলকে by GoldColor by fishColor পরিবর্তন করুন।
class Plecostomus(fishColor: FishColor = GoldColor):  FishAction,
       FishColor by fishColor {
   override fun eat() {
       println("eat algae")
   }
}

ধাপ 4: FishAction এর জন্য ইন্টারফেস প্রতিনিধি যোগ করুন

একইভাবে, আপনি FishAction এর জন্য ইন্টারফেস প্রতিনিধিত্ব ব্যবহার করতে পারেন।

  1. AquariumFish.kt- এ একটি PrintingFishAction ক্লাস তৈরি করুন যা FishAction প্রয়োগ করে, যা একটি String , food নেয়, তারপর মাছ যা খায় তা প্রিন্ট করে।
class PrintingFishAction(val food: String) : FishAction {
    override fun eat() {
        println(food)
    }
}
  1. Plecostomus ক্লাসে, ওভাররাইড ফাংশন eat() সরিয়ে ফেলুন, কারণ আপনি এটিকে একটি প্রতিনিধি দিয়ে প্রতিস্থাপন করবেন।
  2. প্লেকোস্টোমাসের ঘোষণায়, Plecostomus PrintingFishAction FishAction অর্পণ করুন, "eat algae"
  3. এই সমস্ত প্রতিনিধিত্বের সাথে, Plecostomus ক্লাসের শরীরে কোন কোড নেই, তাই {} সরিয়ে দিন, কারণ সমস্ত ওভাররাইড ইন্টারফেস প্রতিনিধি দ্বারা পরিচালিত হয়
class Plecostomus (fishColor: FishColor = GoldColor):
        FishAction by PrintingFishAction("eat algae"),
        FishColor by fishColor

নিম্নোক্ত চিত্রটি Shark এবং Plecostomus শ্রেণীর প্রতিনিধিত্ব করে, উভয়ই PrintingFishAction ফিশঅ্যাকশন এবং FishColor ইন্টারফেসের সমন্বয়ে গঠিত, কিন্তু তাদের বাস্তবায়নের দায়িত্ব অর্পণ করে।

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

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

ধাপ 1: একটি ডেটা ক্লাস তৈরি করুন

  1. নতুন কোড ধরে রাখতে example.myapp প্যাকেজের অধীনে একটি নতুন প্যাকেজ decor যোগ করুন। প্রজেক্ট ফলকে example.myapp- এ রাইট-ক্লিক করুন এবং File > New > Package নির্বাচন করুন।
  2. প্যাকেজে, Decoration নামে একটি নতুন ক্লাস তৈরি করুন।
package example.myapp.decor

class Decoration {
}
  1. Decoration ডেটা ক্লাস করতে, কীওয়ার্ড data সাথে ক্লাস ডিক্লারেশনের উপসর্গ দিন।
  2. ক্লাসকে কিছু ডেটা দিতে rocks নামক একটি String প্রপার্টি যোগ করুন।
data class Decoration(val rocks: String) {
}
  1. ফাইলে, ক্লাসের বাইরে, একটি makeDecorations() ফাংশন যোগ করুন যাতে "granite" দিয়ে Decoration একটি উদাহরণ তৈরি এবং প্রিন্ট করা যায়।
fun makeDecorations() {
    val decoration1 = Decoration("granite")
    println(decoration1)
}
  1. makeDecorations() কল করতে একটি main() ফাংশন যোগ করুন এবং আপনার প্রোগ্রাম চালান। বুদ্ধিমান আউটপুটটি লক্ষ্য করুন যা তৈরি করা হয়েছে কারণ এটি একটি ডেটা ক্লাস।
⇒ Decoration(rocks=granite)
  1. makeDecorations() -এ, আরও দুটি Decoration বস্তুকে ইনস্ট্যান্টিয়েট করুন যেগুলি উভয়ই "স্লেট" এবং সেগুলি মুদ্রণ করুন।
fun makeDecorations() {
    val decoration1 = Decoration("granite")
    println(decoration1)

    val decoration2 = Decoration("slate")
    println(decoration2)

    val decoration3 = Decoration("slate")
    println(decoration3)
}
  1. makeDecorations() এ, একটি প্রিন্ট স্টেটমেন্ট যোগ করুন যা decoration2 এর সাথে decoration1 তুলনা করার ফলাফল প্রিন্ট করে এবং দ্বিতীয়টি decoration3 এর সাথে decoration2 এর তুলনা করে decoration2 সমান() পদ্ধতি ব্যবহার করুন যা ডেটা ক্লাস দ্বারা সরবরাহ করা হয়।
    println (decoration1.equals(decoration2))
    println (decoration3.equals(decoration2))
  1. আপনার কোড চালান.
⇒ Decoration(rocks=granite)
Decoration(rocks=slate)
Decoration(rocks=slate)
false
true

ধাপ 2. ধ্বংস ব্যবহার করুন

একটি ডেটা অবজেক্টের বৈশিষ্ট্যগুলি পেতে এবং সেগুলিকে ভেরিয়েবলগুলিতে বরাদ্দ করতে, আপনি সেগুলিকে একবারে একটি বরাদ্দ করতে পারেন, এভাবে।

val rock = decoration.rock
val wood = decoration.wood
val diver = decoration.diver

পরিবর্তে, আপনি প্রতিটি সম্পত্তির জন্য একটি ভেরিয়েবল তৈরি করতে পারেন এবং ভেরিয়েবলের গ্রুপে ডেটা অবজেক্ট বরাদ্দ করতে পারেন। কোটলিন প্রতিটি ভেরিয়েবলে সম্পত্তির মান রাখে।

val (rock, wood, diver) = decoration

একে ডেস্ট্রাকচারিং বলা হয় এবং এটি একটি দরকারী শর্টহ্যান্ড। ভেরিয়েবলের সংখ্যা বৈশিষ্ট্যের সংখ্যার সাথে মিলিত হওয়া উচিত এবং ভেরিয়েবলগুলি ক্লাসে ঘোষিত ক্রম অনুসারে বরাদ্দ করা হয়। এখানে একটি সম্পূর্ণ উদাহরণ আপনি Decoration.kt এ চেষ্টা করতে পারেন।

// Here is a data class with 3 properties.
data class Decoration2(val rocks: String, val wood: String, val diver: String){
}

fun makeDecorations() {
    val d5 = Decoration2("crystal", "wood", "diver")
    println(d5)

// Assign all properties to variables.
    val (rock, wood, diver) = d5
    println(rock)
    println(wood)
    println(diver)
}
⇒ Decoration2(rocks=crystal, wood=wood, diver=diver)
crystal
wood
diver

আপনার যদি এক বা একাধিক বৈশিষ্ট্যের প্রয়োজন না হয়, তাহলে আপনি একটি পরিবর্তনশীল নামের পরিবর্তে _ ব্যবহার করে সেগুলি এড়িয়ে যেতে পারেন, যেমনটি নীচের কোডে দেখানো হয়েছে।

    val (rock, _, diver) = d5

এই টাস্কে, আপনি কোটলিনের কিছু বিশেষ-উদ্দেশ্য ক্লাস সম্পর্কে শিখবেন, যার মধ্যে নিম্নলিখিতগুলি রয়েছে:

  • সিঙ্গেলটন ক্লাস
  • এনামস
  • সিল করা ক্লাস

ধাপ 1: সিঙ্গলটন ক্লাস প্রত্যাহার করুন

GoldColor ক্লাসের সাথে আগের উদাহরণটি স্মরণ করুন।

object GoldColor : FishColor {
   override val color = "gold"
}

GoldColor প্রতিটি উদাহরণ একই জিনিস করার কারণে, এটিকে সিঙ্গলটন করার জন্য এটিকে class হিসাবে না করে একটি object হিসাবে ঘোষণা করা হয়। এর একটি মাত্র উদাহরণ হতে পারে।

ধাপ 2: একটি enum তৈরি করুন

Kotlin এছাড়াও enums সমর্থন করে, যা আপনাকে কিছু গণনা করতে এবং নাম দ্বারা উল্লেখ করতে দেয়, অনেকটা অন্যান্য ভাষার মতো। enum কীওয়ার্ড দিয়ে ঘোষণার উপসর্গ দিয়ে একটি enum ঘোষণা করুন। একটি মৌলিক enum ঘোষণার শুধুমাত্র নামের একটি তালিকা প্রয়োজন, তবে আপনি প্রতিটি নামের সাথে যুক্ত এক বা একাধিক ক্ষেত্র সংজ্ঞায়িত করতে পারেন।

  1. Decoration.kt- এ, একটি enum-এর উদাহরণ চেষ্টা করে দেখুন।
enum class Color(val rgb: Int) {
   RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);
}

এনামগুলি কিছুটা সিঙ্গেলটনের মতো—এখানে শুধুমাত্র একটি হতে পারে, এবং গণনার প্রতিটি মানের মধ্যে একটি মাত্র। উদাহরণ স্বরূপ, শুধুমাত্র একটি Color.RED , একটি Color.GREEN , এবং একটি Color.BLUE হতে পারে৷ এই উদাহরণে, রঙের উপাদানগুলিকে উপস্থাপন করার জন্য RGB মানগুলি rgb সম্পত্তিতে বরাদ্দ করা হয়েছে। আপনি ordinal প্রপার্টি ব্যবহার করে একটি enum এর ক্রমিক মান এবং name সম্পত্তি ব্যবহার করে এর নাম পেতে পারেন।

  1. একটি enum আরেকটি উদাহরণ চেষ্টা করুন.
enum class Direction(val degrees: Int) {
    NORTH(0), SOUTH(180), EAST(90), WEST(270)
}

fun main() {
    println(Direction.EAST.name)
    println(Direction.EAST.ordinal)
    println(Direction.EAST.degrees)
}
⇒ EAST
2
90

ধাপ 3: একটি সিল করা ক্লাস তৈরি করুন

একটি সিল করা শ্রেণী হল এমন একটি শ্রেণী যাকে সাবক্লাস করা যেতে পারে, কিন্তু শুধুমাত্র সেই ফাইলের ভিতরে যেখানে এটি ঘোষণা করা হয়েছে। আপনি যদি একটি ভিন্ন ফাইলে ক্লাসটি সাবক্লাস করার চেষ্টা করেন তবে আপনি একটি ত্রুটি পাবেন।

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

  1. AquariumFish.kt- এ, জলজ থিম রেখে একটি সিল করা ক্লাসের উদাহরণ চেষ্টা করুন।
sealed class Seal
class SeaLion : Seal()
class Walrus : Seal()

fun matchSeal(seal: Seal): String {
   return when(seal) {
       is Walrus -> "walrus"
       is SeaLion -> "sea lion"
   }
}

Seal ক্লাস অন্য ফাইলে সাবক্লাস করা যাবে না। আপনি যদি আরও Seal প্রকার যোগ করতে চান তবে আপনাকে সেগুলি একই ফাইলে যুক্ত করতে হবে। এটি নির্দিষ্ট সংখ্যক প্রকারের প্রতিনিধিত্ব করার জন্য সিল করা ক্লাসগুলিকে একটি নিরাপদ উপায় করে তোলে। উদাহরণস্বরূপ, একটি নেটওয়ার্ক API থেকে সাফল্য বা ত্রুটি ফেরত দেওয়ার জন্য সিল করা ক্লাসগুলি দুর্দান্ত৷

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

ক্লাস এবং কনস্ট্রাক্টর

  • class ব্যবহার করে কোটলিনে একটি ক্লাস সংজ্ঞায়িত করুন।
  • Kotlin স্বয়ংক্রিয়ভাবে বৈশিষ্ট্যের জন্য সেটার এবং গেটার তৈরি করে।
  • শ্রেণী সংজ্ঞায় সরাসরি প্রাথমিক কনস্ট্রাক্টর সংজ্ঞায়িত করুন। উদাহরণ স্বরূপ:
    class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40)
  • যদি একটি প্রাথমিক কনস্ট্রাক্টরের অতিরিক্ত কোডের প্রয়োজন হয়, এটি এক বা একাধিক init ব্লকে লিখুন।
  • একটি শ্রেণী কনস্ট্রাক্টর ব্যবহার করে এক বা একাধিক মাধ্যমিক constructor সংজ্ঞায়িত করতে পারে, কিন্তু কোটলিন শৈলী হল এর পরিবর্তে একটি ফ্যাক্টরি ফাংশন ব্যবহার করা।

দৃশ্যমানতা পরিবর্তনকারী এবং উপশ্রেণী

  • Kotlin-এর সমস্ত ক্লাস এবং ফাংশন ডিফল্টরূপে public , কিন্তু আপনি দৃশ্যমানতাকে internal , private বা protected তে পরিবর্তন করতে মডিফায়ার ব্যবহার করতে পারেন।
  • একটি সাবক্লাস তৈরি করতে, প্যারেন্ট ক্লাসকে অবশ্যই open চিহ্নিত করতে হবে।
  • একটি সাবক্লাসে পদ্ধতি এবং বৈশিষ্ট্যগুলিকে ওভাররাইড করতে, পদ্ধতি এবং বৈশিষ্ট্যগুলিকে প্যারেন্ট ক্লাসে open চিহ্নিত করতে হবে।
  • একটি সিল করা শ্রেণী শুধুমাত্র একই ফাইলে সাবক্লাস করা যেতে পারে যেখানে এটি সংজ্ঞায়িত করা হয়েছে। সিল দিয়ে ঘোষণার উপসর্গ দিয়ে একটি sealed করা ক্লাস তৈরি করুন।

ডেটা ক্লাস, সিঙ্গেলটন এবং এনাম

  • ডেটার সাথে ঘোষণার উপসর্গ দিয়ে একটি data ক্লাস তৈরি করুন।
  • ডিস্ট্রাকচারিং হল আলাদা ভেরিয়েবলের জন্য data অবজেক্টের বৈশিষ্ট্য বরাদ্দ করার জন্য একটি সংক্ষিপ্ত বিবরণ।
  • class পরিবর্তে object ব্যবহার করে একটি সিঙ্গলটন ক্লাস তৈরি করুন।
  • enum class ব্যবহার করে একটি enum সংজ্ঞায়িত করুন।

বিমূর্ত ক্লাস, ইন্টারফেস, এবং প্রতিনিধি

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

কোটলিন ডকুমেন্টেশন

If you want more information on any topic in this course, or if you get stuck, https://kotlinlang.org is your best starting point.

Kotlin tutorials

The https://try.kotlinlang.org website includes rich tutorials called Kotlin Koans, a web-based interpreter , and a complete set of reference documentation with examples.

Udacity course

To view the Udacity course on this topic, see Kotlin Bootcamp for Programmers .

IntelliJ IDEA

Documentation for the IntelliJ IDEA can be found on the JetBrains website.

This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:

  • Assign homework if required.
  • Communicate to students how to submit homework assignments.
  • Grade the homework assignments.

Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.

If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.

Answer these questions

Question 1

Classes have a special method that serves as a blueprint for creating objects of that class. What is the method called?

▢ A builder

▢ An instantiator

▢ A constructor

▢ A blueprint

Question 2

Which of the following statements about interfaces and abstract classes is NOT correct?

▢ Abstract classes can have constructors.

▢ Interfaces can't have constructors.

▢ Interfaces and abstract classes can be instantiated directly.

▢ Abstract properties must be implemented by subclasses of the abstract class.

Question 3

Which of the following is NOT a Kotlin visibility modifier for properties, methods, etc.?

internal

nosubclass

protected

private

Question 4

Consider this data class:
data class Fish(val name: String, val species:String, val colors:String)
Which of the following is NOT valid code to create and destructure a Fish object?

val (name1, species1, colors1) = Fish("Pat", "Plecostomus", "gold")

val (name2, _, colors2) = Fish("Bitey", "shark", "gray")

val (name3, species3, _) = Fish("Amy", "angelfish", "blue and black stripes")

val (name4, species4, colors4) = Fish("Harry", "halibut")

Question 5

Let's say you own a zoo with lots of animals that all need to be taken care of. Which of the following would NOT be part of implementing caretaking?

▢ An interface for different types of foods animals eat.

▢ An abstract Caretaker class from which you can create different types of caretakers.

▢ An interface for giving clean water to an animal.

▢ A data class for an entry in a feeding schedule.

Proceed to the next lesson: 5.1 Extensions

For an overview of the course, including links to other codelabs, see "Kotlin Bootcamp for Programmers: Welcome to the course."