آموزش جاوا - انتزاع
بر اساس فرهنگ لغت، انتزاع کیفیت مرتبط با معامله با ایدهها به جای رویدادهاست. به عنوان مثال، وقتی شما به مورد ایمیل فکر میکنید، جزئیات پیچیدهای مانند اتفاقاتی که به طور فوری پس از ارسال ایمیل رخ میدهد و پروتکلی که سرور ایمیل شما استفاده میکند، برای کاربر پنهان است. بنابراین، برای ارسال یک ایمیل، شما فقط باید متن مورد نظر را تایپ کنید، آدرس گیرنده را مشخص کنید و دکمه ارسال را کلیک کنید.
به همین ترتیب در برنامهنویسی شیگرا، انتزاع فرآیندی است که جزئیات اجرایی را از کاربر مخفی میکند و تنها قابلیتها برای کاربر ارائه میشود. به عبارت دیگر، کاربر فقط اطلاعاتی در مورد عملکرد شی را مشاهده میکند و نحوه انجام آن را مشاهده نمیکند
در جاوا، انتزاع با استفاده از کلاسهای انتزاعی و رابطها (interfaces) به دست میآید.
کلاس انتزاعی (Abstract Class)
کلاسی که در تعریف خود از کلمه کلیدی abstract استفاده میکند به عنوان کلاس انتزاعی شناخته میشود.
-
کلاسهای انتزاعی ممکن است حاوی متدهای انتزاعی یا به عبارتی متدهایی بدون بدنه (public void get();) باشند.
-
اما، اگر یک کلاس حداقل یک متد انتزاعی داشته باشد، آن کلاس باید به صورت انتزاعی تعریف شود.
-
اگر یک کلاس به صورت انتزاعی تعریف شود، قابل نمونهسازی نخواهد بود.
-
برای استفاده از یک کلاس انتزاعی، باید آن را از یک کلاس دیگر به ارث ببرید و پیادهسازیهایی را برای متدهای انتزاعی در آن ارائه دهید.
-
اگر از یک کلاس انتزاعی ارث بری کنید، باید پیادهسازیهایی را برای تمامی متدهای انتزاعی در آن ارائه دهید.
مثال
این بخش شما را با یک نمونه از کلاس انتزاعی آشنا میکند. برای ایجاد یک کلاس انتزاعی، کافیست قبل از کلمه کلیدی class در تعریف کلاس، از کلمه کلیدی abstract استفاده کنید.
/* File name : Employee.java */
public abstract class Employee {
private String name;
private String address;
private int number;
public Employee(String name, String address, int number) {
System.out.println("Constructing an Employee");
this.name = name;
this.address = address;
this.number = number;
}
public double computePay() {
System.out.println("Inside Employee computePay");
return 0.0;
}
public void mailCheck() {
System.out.println("Mailing a check to " + this.name + " " + this.address);
}
public String toString() {
return name + " " + address + " " + number;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public void setAddress(String newAddress) {
address = newAddress;
}
public int getNumber() {
return number;
}
}
میتوانید مشاهده کنید که به جز متدهای انتزاعی، کلاس Employee مشابه یک کلاس عادی در جاوا است. این کلاس اکنون انتزاعی است، اما همچنان سه فیلد، هفت متد و یک سازنده دارد.
اکنون میتوانید تلاش کنید کلاس Employee را به شکل زیر نمونهسازی کنید:
/* File name : AbstractDemo.java */
public class AbstractDemo {
public static void main(String [] args) {
/* Following is not allowed and would raise error */
Employee e = new Employee("George W.", "Houston, TX", 43);
System.out.println("\n Call mailCheck using Employee reference--");
e.mailCheck();
}
}
وقتی کد فوق را کامپایل میکنید، خطا زیر را دریافت میکنید:
Employee.java:46: Employee is abstract; cannot be instantiated
Employee e = new Employee("George W.", "Houston, TX", 43);
^
1 error
ارثبرداری از کلاس انتزاعی (Inheriting the Abstract Class)
ما میتوانیم خواص کلاس Employee را به همان شکل کلاس معمولی به ارث ببریم به صورت زیر:
مثال
/* File name : Salary.java */
public class Salary extends Employee {
private double salary; // Annual salary
public Salary(String name, String address, int number, double salary) {
super(name, address, number);
setSalary(salary);
}
public void mailCheck() {
System.out.println("Within mailCheck of Salary class ");
System.out.println("Mailing check to " + getName() + " with salary " + salary);
}
public double getSalary() {
return salary;
}
public void setSalary(double newSalary) {
if(newSalary >= 0.0) {
salary = newSalary;
}
}
public double computePay() {
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
}
در اینجا، شما نمیتوانید نمونهای از کلاس Employee ایجاد کنید، اما میتوانید نمونهای از کلاس Salary ایجاد کنید و با استفاده از این نمونه، به همه سه فیلد و هفت متد کلاس Employee دسترسی داشته باشید همانطور که در زیر نشان داده شده است.
/* File name : AbstractDemo.java */
public class AbstractDemo {
public static void main(String [] args) {
Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
System.out.println("Call mailCheck using Salary reference --");
s.mailCheck();
System.out.println("\n Call mailCheck using Employee reference--");
e.mailCheck();
}
}
این عمل، نتیجه زیر را تولید میکند:
خروجی
Constructing an Employee
Constructing an Employee
Call mailCheck using Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0
Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.0
متدهای انتزاعی (Abstract Methods)
اگر میخواهید یک کلاس حاوی یک متد خاص باشد، اما میخواهید پیادهسازی واقعی آن متد توسط کلاسهای فرزند تعیین شود، میتوانید متد را در کلاس والدین به عنوان یک متد انتزاعی تعریف کنید.
-
کلمه کلیدی abstract برای تعریف متد به عنوان یک متد انتزاعی استفاده میشود.
-
باید کلمه کلیدی abstract را قبل از نام متد در تعریف متد قرار دهید.
-
یک متد انتزاعی حاوی امضای متد است، اما بدنهای برای متد ندارد.
-
به جای براکتهای آکولاد، یک متد انتزاعی در انتها دارای علامت سمیکالن (;) خواهد بود.
مثالی از متد انتزاعی در زیر آورده شده است:
مثال
public abstract class Employee {
private String name;
private String address;
private int number;
public abstract double computePay();
// Remainder of class definition
}
تعریف یک متد به عنوان انتزاعی دو پیامد دارد:
-
کلاس حاوی آن باید به عنوان یک کلاس انتزاعی تعریف شود.
-
هر کلاسی که از کلاس فعلی به ارث برده شود، باید یا متد انتزاعی را بازنویسی کند یا خود را به عنوان یک کلاس انتزاعی تعریف کند.
توجه − در نهایت، یک کلاس فرزند باید متد انتزاعی را پیادهسازی کند؛ در غیر این صورت، شما یک سلسلهمراتب از کلاسهای انتزاعی بدون امکان نمونهسازی خواهید داشت.
فرض کنید کلاس Salary از کلاس Employee ارث ببرد، سپس باید متد computePay() را پیادهسازی کند همانطور که در زیر نشان داده شده است:
/* File name : Salary.java */
public class Salary extends Employee {
private double salary; // Annual salary
public double computePay() {
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
// Remainder of class definition
}