1. ইন্টারফেস প্রবর্তন

আজ আপনার জ্ঞানের দিন। আরেকটি নতুন এবং আকর্ষণীয় বিষয় হল ইন্টারফেস।

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

interface Feline
{
   void purr();
   void meow();
   void growl();
}

এখানে ইন্টারফেস সম্পর্কে কিছু দরকারী তথ্য আছে:

1. একটি ইন্টারফেস ঘোষণা করা

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. কীওয়ার্ডের পরিবর্তে class, আমরা লিখি interface
  2. এটিতে শুধুমাত্র বিমূর্ত পদ্ধতি রয়েছে (কীওয়ার্ড লিখবেন না abstract)
  3. আসলে, ইন্টারফেসে সবpublic পদ্ধতি আছে
2. ইন্টারফেস উত্তরাধিকার

একটি ইন্টারফেস শুধুমাত্র ইন্টারফেসের উত্তরাধিকারী হতে পারে। কিন্তু একটি ইন্টারফেসে অনেক অভিভাবক থাকতে পারে। এটি বলার আরেকটি উপায় হল জাভা ইন্টারফেসের একাধিক উত্তরাধিকার রয়েছে। উদাহরণ:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. ইন্টারফেস থেকে ক্লাস ইনহেরিট করা

একটি ক্লাস একাধিক ইন্টারফেস উত্তরাধিকারী হতে পারে (শুধুমাত্র একটি শ্রেণী থেকে)। এটি implementsকীওয়ার্ড ব্যবহার করে করা হয়। উদাহরণ:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

ChessItem ক্লাসটিকে বিমূর্ত ঘোষণা করা হয়েছে: এটি ব্যতীত উত্তরাধিকার সূত্রে প্রাপ্ত সমস্ত পদ্ধতি প্রয়োগ করে drawঅন্য কথায়, ChessItemক্লাসে একটি বিমূর্ত পদ্ধতি রয়েছে — draw()

extendsএবং কীওয়ার্ডের প্রযুক্তিগত অর্থ implementsএকই: উভয়ই উত্তরাধিকার। পার্থক্যটি কোডের পঠনযোগ্যতা উন্নত করার জন্য করা হয়েছিল। আমরা আরও বলি যে ক্লাসগুলি উত্তরাধিকারসূত্রে প্রাপ্ত হয় (এর মাধ্যমে extends) এবং ইন্টারফেসগুলি প্রয়োগ করা হয় (এর মাধ্যমে implements)

4. ভেরিয়েবল

এখানে সবচেয়ে গুরুত্বপূর্ণ বিষয় হল: সাধারণ ভেরিয়েবলগুলি ইন্টারফেসে ঘোষণা করা যায় না (যদিও স্ট্যাটিকগুলি করতে পারে)।

কিন্তু কেন আমরা ইন্টারফেস প্রয়োজন? তারা কখন ব্যবহার করা হয়? ক্লাসের তুলনায় ইন্টারফেসের দুটি শক্তিশালী সুবিধা রয়েছে:



2. তাদের বাস্তবায়ন থেকে "পদ্ধতির বিবরণ" আলাদা করা।

পূর্বে, আমরা বলেছিলাম যে আপনি যদি আপনার ক্লাসের পদ্ধতিগুলিকে অন্য ক্লাস থেকে কল করার অনুমতি দিতে চান তবে আপনার পদ্ধতিগুলিকে কীওয়ার্ড দিয়ে চিহ্নিত করতে হবে publicআপনি যদি চান যে এই পদ্ধতিগুলির মধ্যে কয়েকটি শুধুমাত্র আপনার ক্লাসের মধ্যে থেকে কল করা হোক, আপনাকে কীওয়ার্ড দিয়ে চিহ্নিত করতে হবে private। অন্য কথায়, আমরা ক্লাসের পদ্ধতিগুলিকে দুটি ভাগে ভাগ করি: "প্রত্যেকের ব্যবহারের জন্য" এবং "শুধুমাত্র আমাদের নিজস্ব ব্যবহারের জন্য"।

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

আগে পরে
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

আমরা আমাদের ক্লাসকে দুটি ভাগে বিভক্ত করেছি: একটি ইন্টারফেস এবং একটি ক্লাস যা ইন্টারফেসের উত্তরাধিকারসূত্রে প্রাপ্ত । এবং এখানে সুবিধা কি?

অনেকগুলি বিভিন্ন ক্লাস একই ইন্টারফেস বাস্তবায়ন (উত্তরাধিকারী) করতে পারে। এবং প্রত্যেকের নিজস্ব আচরণ থাকতে পারে। উদাহরণস্বরূপ, ArrayList LinkedListইন্টারফেসের দুটি ভিন্ন বাস্তবায়ন List

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

পলিমরফিজমের সাথে মিলিত হলে এটি একটি খুব শক্তিশালী কৌশল। আপাতত, কেন এটি করা উচিত তা স্পষ্ট নয়। ইন্টারফেসগুলি আপনার জীবনকে সেগুলি ছাড়ার চেয়ে অনেক সহজ করে তুলতে পারে তা বোঝার জন্য আপনাকে প্রথমে কয়েক ডজন বা শত শত ক্লাসের সাথে প্রোগ্রামগুলির মুখোমুখি হতে হবে।


3. একাধিক উত্তরাধিকার

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

জাভার নির্মাতারা একটি সমঝোতায় পৌঁছেছেন: তারা ক্লাসের একাধিক উত্তরাধিকার নিষিদ্ধ করেছে, কিন্তু ইন্টারফেসের একাধিক উত্তরাধিকারের অনুমতি দিয়েছে। একটি ইন্টারফেসে একাধিক প্যারেন্ট ইন্টারফেস থাকতে পারে। একটি ক্লাসে একাধিক অভিভাবক ইন্টারফেস থাকতে পারে তবে শুধুমাত্র একটি অভিভাবক শ্রেণী থাকতে পারে।

কেন তারা ক্লাসের একাধিক উত্তরাধিকার নিষিদ্ধ করেছে কিন্তু ইন্টারফেসের একাধিক উত্তরাধিকারের অনুমতি দিয়েছে? তথাকথিত হীরার উত্তরাধিকার সমস্যার কারণে:

একাধিক উত্তরাধিকার

যখন B শ্রেণী A ক্লাসের উত্তরাধিকারী হয়, তখন এটি C এবং D শ্রেণী সম্পর্কে কিছুই জানে না। সুতরাং এটি A ক্লাসের ভেরিয়েবলগুলিকে উপযুক্ত হিসাবে ব্যবহার করে। সি ক্লাস একই কাজ করে: এটি A ক্লাসের ভেরিয়েবল ব্যবহার করে, কিন্তু ভিন্ন উপায়ে। আর এই সবের ফলে ডি শ্রেণীতে দ্বন্দ্ব দেখা দেয়।

আসুন নিম্নলিখিত সহজ উদাহরণ তাকান. ধরা যাক আমাদের 3টি ক্লাস আছে:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

ডেটা ক্লাস valueভেরিয়েবল সংরক্ষণ করে। এর XCoordinate descendant ক্লাস মান সংরক্ষণ করতে সেই ভেরিয়েবলটি ব্যবহার করে x, এবং descendant ক্লাস মান YCoordinateসংরক্ষণ করতে এটি ব্যবহার করে ।y

এবং এটি কাজ করে। আলাদাভাবে। কিন্তু যদি আমরা চাই XYCoordinates ক্লাস XCoordinateএবং YCoordinateক্লাস উভয়ের উত্তরাধিকারী হয়, তাহলে আমরা ভাঙা কোড পাই। এই ক্লাসের পূর্বপুরুষ ক্লাসের পদ্ধতি থাকবে, কিন্তু তারা সঠিকভাবে কাজ করবে না, কারণ তাদের একই আছে value variable

কিন্তু যেহেতু ইন্টারফেসে ভেরিয়েবল থাকতে পারে না, তাই তাদের এই ধরনের দ্বন্দ্ব থাকতে পারে না। তদনুসারে, ইন্টারফেসের একাধিক উত্তরাধিকার অনুমোদিত।