برنامه نویسی 1386 بازدید

در این مقاله به بررسی مفاهیم برنامه نویسی شی‌گرا از جمله مفهوم کلاس در برنامه نویسی جاوا می‌پردازیم. در این زمینه مفاهیم کلاس، شی ، تجرید، کپسوله‌سازی، وراثت و چندریختی مورد بررسی قرار خواهند گرفت.

کلاس

کلاس نقطه شروع همه اشیا محسوب می‌شود. کلاس را می‌توان به عنوان یک قالب برای ایجاد شیئ تصور کرد. هر کلاس به طور معمول شامل فیلدهای عضو، متدهای عضو، و یک متد خاص به نام «سازنده» (constructor) است. ما از این متد سازنده برای ساخت اشیایی از روی کلاس استفاده می‌کنیم:

public class Car {
  
    // member fields
    private String type;
    private String model;
    private String color;
    private int speed;
  
    // constructor
    public Car(String type, String model, String color) {
        this.type = type;
        this.model = model;
        this.color = color;
    }
      
    // member methods
    public int increaseSpeed(int increment) {
        this.speed = this.speed + increment;
        return this.speed;
    }
      
    // ...
}

توجه کنید که کلاس می‌تواند بیش از یک سازنده داشته باشد.

شیئ

شیءها از کلاس‌ها ساخته می‌شوند و به صورت نمونه‌هایی (Instanse) از کلاس نامیده می‌شوند. بدین ترتیب اشیا با استفاده از سازنده‌ها از کلاس‌ها ساخته می‌شوند:

Car veyron = new Car("Bugatti", "Veyron", "crimson");
Car corvette = new Car("Chevrolet", "Corvette", "black");

در کد فوق دو وهله از کلاس Car ایجاد کرده‌ایم.

تجرید

وظیفه «تجرید» (Abstraction) پنهان‌سازی پیچیدگی‌های پیاده‌سازی و عرضه اینترفیس‌های ساده‌تر است. برای نمونه اگر یک رایانه را در نظر بگیریم، ما تنها اینترفیس بیرونی آن را می‌بینیم که شامل ضروری‌ترین موارد مورد نیاز برای تعامل با آن است، در حالی که تراشه‌ها و مدارهای داخلی رایانه از دید کاربر پنهان شده است. در برنامه‌نویسی شیئ گرا تجرید به معنی پنهان کردن جزییات پیچیده پیاده‌سازی یک برنامه است. بدین ترتیب صرفاً API مورد نیاز برای استفاده از پیاده‌سازی عرضه می‌شود. در جاوا با استفاده از اینترفیس‌ها و «کلاس‌های مجرد» (Abstract Classes) به تجرید دست پیدا می‌کنیم.

کپسوله‌سازی

وظیفه مفهوم «کپسوله‌سازی» (Encapsulation) پنهان‌سازی حالت بازنمایی داخلی یک شیئ از مصرف‌کننده API است. بدین ترتیب متدهای با دسترسی عمومی متصل به شیئ برای دسترسی‌های خواندن-نوشتن عرضه می‌شوند. این مفهوم امکان پنهان‌سازی اطلاعات خاص و کنترل کردن دسترسی به پیاده‌سازی داخلی را فراهم می‌سازد.

برای نمونه فیلدهای عضو در یک کلاس از دیگر کلاس‌ها پنهان هستند و با استفاده از متدهای عضو می‌توانیم به آن‌ها دسترسی پیدا کنیم. یک روش برای انجام این کار خصوصی ساختن همه فیلدهای داده است که موجب می‌شود تنها از طریق متدهای عضو عمومی قابل دسترسی باشند:

public class Car {
 
    // ...
    private int speed;
 
    public int getSpeed() {
        return color;
    }
 
    public void setSpeed(int speed) {
        this.speed = speed;
    }
    // ...
}

در کلاس فوق، speed با استفاده از مادیفایر دسترسی private به صورت خصوصی در آمده است و تنها از طریق متدهای عمومی ()getSpeed و ()setSpeed قابل دسترسی است.

وراثت

مفهوم «وراثت» (Inheritance) مکانیسمی است که امکان دست یافتن به همه مشخصه‌های یک کلاس را در کلاس دیگر فراهم می‌سازد. این کلاس وارث را کلاس فرزند می‌نامیم و کلاس ارث دهنده به صورت کلاس والد یا «سوپرکلاس» (superclass) نامیده می‌شود. در جاوا این کار از طریق بسط دادن کلاس والد انجام می‌یابد. از این رو کلاس فرزند همه مشخصه‌های خود را از والد به ارث می‌برد:

public class Car extends Vehicle { 
    //...
}

هنگامی که یک کلاس بسط می‌یابد، یک رابطه «است» شکل می‌گیرد. بدین ترتیب خودرو (Car) یک وسیله نقلیه (Vihicle) «است» و از این رو همه مشخصات یک وسیله نقلیه را دارد.

ممکن است بپرسید چرا به وراثت نیاز داریم؟ برای پاسخ به این سؤال، سازنده یک وسیله نقلیه را فرض کنید که انواع مختلفی از وسایل نقلیه مانند خودروی سواری، اتوبوس، وانت یا کامیون را می‌سازد. برای ساده‌تر شدن کارها می‌توانیم ویژگی‌ها و مشخصه‌های مشترک را برای همه انواع وسیله نقلیه در یک ماژول (در جاوا کلاس نام دارد) بسازیم. سپس می‌توانیم در مورد انواع منفرد این مشخصه‌ها را از آن ماژول مشترک ارث‌بری کرده و آن مشخصه‌ها را مورد استفاده مجدد قرار دهیم:

public class Vehicle {
    private int wheels;
    private String model;
    public void start() {
        // the process of starting the vehicle
    }
     
    public void stop() {
        // process to stop the vehicle
    }
     
    public void honk() { 
        // produces a default honk 
    }
 
}

بدین ترتیب یک Car از نوع Vehicle می‌تواند مشخصه‌های خود را از کلاس Vehicle والد به ارث ببرد:

public class Car extends Vehicle {
    private int numberOfGears;
 
    public void openDoors() {
        // process to open the doors
    }
}

جاوا از وراثت منفرد و چند سطحی پشتیبانی می‌کند. این بدان معنی است که یک کلاس نمی‌تواند مستقیماً از بیش از یک کلاس ارث‌بری کند. اما می‌توان از یک سلسله‌مراتب استفاده کرد:

public class ArmoredCar extends Car {
    private boolean bulletProofWindows;
     
    public void remoteStartCar() {
        // this vehicle can be started by using a remote control
    }
}

بدین ترتیب ArmouredCar اقدام به بسط Car می‌کند و Car نیز Vehicle را بسط می‌دهد. از این رو ArmouredCar مشخصه‌های خود را از هر دو کلاس Car و Vehicle ارث‌بری می‌کند. توسعه‌دهندگان در زمان ارث‌بری از کلاس والد می‌توانند برخی پیاده‌سازی‌های متد مربوط به والد را نیز باطل (Override) کنند. این کار به نام «باطل سازی متد» (method overriding) نامیده می‌شود. در مثال مورد بحث ما در مورد کلاس Vehicle یک متد به نام ()honk وجود دارد. کلاس Car اقدام به بسط کلاس Vehicle می‌کند و می‌تواند این متد را باطل کرده و آن را به روشی که می‌خواهد «بوق» (honk) را تولید کند، پیاده‌سازی نماید:

public class Car extends Vehicle {  
    //...
 
    @Override
    public void honk() { 
        // produces car-specific honk 
    }
 }

توجه داشته باشید که این وضعیت به نام «چندریختی زمان اجرا» (runtime polymorphism) نیز نامیده می‌شود که در بخش بعدی آن را بیشتر توضیح خواهیم داد.

چندریختی

«چندریختی» (Polymorphism) به امکان زبان‌های برنامه‌نویسی شیئ‌گرا برای تولید پردازش داده‌ها به روش‌های متفاوت بسته به انواع ورودی‌ها گفته می‌شود. این وضعیت در جاوا از طریق ایجاد متدها با نام یکسان و امضای متد متفاوت و اجرای کارکردهای متفاوت انجام می‌یابد:

public class TextFile extends GenericFile {
    //...
  
    public String read() {
        return this.getContent()
          .toString();
    }
  
    public String read(int limit) {
        return this.getContent()
          .toString()
          .substring(0, limit);
    }
  
    public String read(int start, int stop) {
        return this.getContent()
          .toString()
          .substring(start, stop);
    }
}

در این مثال، می‌بینیم که متد ()read سه شکل متفاوت با کارکردهای مختلف دارد. این نوع چندریختی استاتیک یا چندریختی زمان کامپایل نام دارد و گاهی اوقات به نام method overloading نیز نامیده می‌شود یک نوع چندریختی زمان اجرا نیز وجود دارد که به نام چندریختی دینامیک نامیده می‌شود و در آن کلاس فرزند، متدهای والد را باطل می‌کند.

public class GenericFile {
    private String name;
  
    //...
  
    public String getFileInfo() {
        return "Generic File Impl";
    }
}

کلاس فرزند می‌تواند کلاس GenericFile را بسط داده و متد ()getFileInfo را باطل سازد:

public class ImageFile extends GenericFile {
    private int height;
    private int width;
  
    //... getters and setters
      
    public String getFileInfo() {
        return "Image File Impl";
    }
}

سخن پایانی

در این مقاله با مفاهیم اساسی برنامه‌نویسی شیئ‌گرا در جاوا آشنا شدیم. کدهای نمونه معرفی شده در این مقاله را می‌توانید در این ریپوی گیت‌هاب (+) ملاحظه کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.

«میثم لطفی» دانش‌آموخته ریاضیات و شیفته فناوری به خصوص در حوزه رایانه است. وی در حال حاضر علاوه بر پیگیری علاقه‌مندی‌هایش در رشته‌های برنامه‌نویسی، کپی‌رایتینگ و محتوای چندرسانه‌ای، در زمینه نگارش مقالاتی با محوریت نرم‌افزار نیز با مجله فرادرس همکاری دارد.

بر اساس رای 3 نفر

آیا این مطلب برای شما مفید بود؟

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *