کلاس انتزاعی (Abstract Class) کلاسی است که با کلمهکلیدی abstract تعریف شده — ممکن است Abstract Method داشته باشد یا نداشته باشد. کلاسهای انتزاعی قابل نمونهسازی (Instantiate) نیستند اما میتوانند زیرکلاس داشته باشند.
متد انتزاعی (Abstract Method) متدی است که بدون پیادهسازی تعریف شده (بدون براکت و با سمیکالن در انتها)، به این شکل:
abstract void moveTo(double deltaX, double deltaY);
اگر کلاسی شامل Abstract Methodها باشد، خود کلاس هم باید abstract تعریف شده باشد، مثل این:
public abstract class GraphicObject {
// declare fields
// declare nonabstract methods
abstract void draw();
}
وقتی کلاس انتزاعی زیرکلاس پیدا میکند، زیرکلاس معمولاً پیادهسازی تمام Abstract Methodهای والد خود را ارائه میدهد. اما اگر این کار را نکند، زیرکلاس هم باید abstract تعریف شده باشد.
---نکته: متدهایی در Interface (بخش Interfaceها را ببینید) که به صورت
defaultیاstaticتعریف نشدهاند، بهصورت ضمنی Abstract هستند، بنابراین ویرایشگر abstract با متدهای Interface استفاده نمیشود. (قابل استفاده است اما ضروری نیست.)
کلاسهای انتزاعی شبیه Interfaceها هستند. نمیتوانید از آنها نمونه بسازید و ممکن است ترکیبی از متدهای تعریفشده با یا بدون پیادهسازی داشته باشند. اما با کلاسهای انتزاعی، میتوانید فیلدهایی تعریف کنید که static و final نیستند، و متدهای public، protected و private پیادهسازیشده تعریف کنید. در Interfaceها، تمام فیلدها بهطور خودکار public، static و final هستند و تمام متدهایی که تعریف یا توصیف میکنید (به صورت Default Methodها) public هستند. علاوه بر این، فقط میتوانید از یک کلاس ارث ببرید، چه abstract باشد چه نباشد، در حالی که میتوانید هر تعداد Interface را پیادهسازی کنید.
کدام را باید استفاده کنید، کلاسهای انتزاعی یا Interfaceها؟
اگر هر یک از این جملات دربارهی وضعیت شما صدق میکند، استفاده از کلاسهای انتزاعی را در نظر بگیرید:
protected و private) نیاز دارند.اگر هر یک از این جملات دربارهی وضعیت شما صدق میکند، استفاده از Interfaceها را در نظر بگیرید:
Comparable و Cloneable توسط کلاسهای غیرمرتبط زیادی پیادهسازی شدهاند.مثالی از کلاس انتزاعی در JDK، کلاس AbstractMap است که بخشی از Collections Framework است. زیرکلاسهایش (شامل HashMap، TreeMap و ConcurrentHashMap) متدهای مشترک زیادی (شامل get()، put()، isEmpty()، containsKey() و containsValue()) دارند که AbstractMap تعریف میکند.
مثالی از کلاسی در JDK که چندین Interface را پیادهسازی میکند، HashMap است که Interfaceهای Serializable، Cloneable و Map<K, V> را پیادهسازی میکند. با خواندن این لیست از Interfaceها میتوان استنباط کرد که یک نمونه از HashMap (صرفنظر از توسعهدهنده یا شرکتی که کلاس را پیادهسازی کرده) قابل Clone شدن است، Serializable است (یعنی قابل تبدیل به Byte Stream است — بخش Serializable Objects را ببینید)، و عملکرد Map را دارد. علاوه بر این، Interface Map<K, V> با Default Methodهای زیادی مثل merge() و forEach() غنی شده که کلاسهای قدیمیتری که این Interface را پیادهسازی کردهاند مجبور به تعریف آنها نیستند.
توجه کنید که بسیاری از کتابخانههای نرمافزاری هم از کلاسهای انتزاعی و هم از Interfaceها استفاده میکنند — کلاس HashMap چندین Interface را پیادهسازی میکند و همچنین از کلاس انتزاعی AbstractMap ارث میبرد.
در یک برنامهی ترسیم شیگرا، میتوانید دایره، مستطیل، خط، منحنی Bezier و اشیای گرافیکی دیگری ترسیم کنید. این اشیا همگی وضعیتهای مشترکی (مثلاً: موقعیت، جهت، رنگ خط، رنگ پرکردن) و رفتارهای مشترکی (مثلاً: moveTo، rotate، resize، draw) دارند. برخی از این وضعیتها و رفتارها برای تمام اشیای گرافیکی یکسان هستند (مثلاً: موقعیت، رنگ پرکردن و moveTo). برخی دیگر به پیادهسازیهای مختلفی نیاز دارند (مثلاً resize یا draw).
تمام GraphicObjectها باید بتوانند خودشان را ترسیم یا تغییر اندازه دهند؛ فقط نحوهی انجام این کار متفاوت است. این یک موقعیت عالی برای یک فوقکلاس انتزاعی است. میتوانید از شباهتها بهره ببرید و تمام اشیای گرافیکی را طوری تعریف کنید که از یک والد انتزاعی مشترک ارث ببرند، مثلاً GraphicObject.
ابتدا یک کلاس انتزاعی، GraphicObject، تعریف میکنید تا متغیرهای عضو و متدهایی که کاملاً توسط تمام زیرکلاسها مشترک هستند (مثل موقعیت فعلی و متد moveTo()) فراهم شوند. GraphicObject همچنین Abstract Methodهایی برای متدهایی مثل draw() یا resize() تعریف میکند که باید توسط تمام زیرکلاسها پیادهسازی شوند اما هر کلاس نحوهی متفاوتی برای انجام این کار دارد. کلاس GraphicObject ممکن است این شکلی باشد:
abstract class GraphicObject {
int x, y;
...
void moveTo(int newX, int newY) {
...
}
abstract void draw();
abstract void resize();
}
هر زیرکلاس غیرانتزاعی از GraphicObject، مثل Circle و Rectangle، باید پیادهسازی متدهای draw() و resize() را ارائه دهند:
class Circle extends GraphicObject {
void draw() {
...
}
void resize() {
...
}
}
class Rectangle extends GraphicObject {
void draw() {
...
}
void resize() {
...
}
}
---
در بخش Interfaceها اشاره شد که کلاسی که Interface پیادهسازی میکند باید تمام متدهای آن Interface را پیادهسازی کند. با این حال، میتوان کلاسی تعریف کرد که تمام متدهای Interface را پیادهسازی نکند، به شرطی که کلاس abstract تعریف شده باشد. مثال:
abstract class X implements Y {
// implements all but one method of Y
}
class XX extends X {
// implements the remaining method in Y
}
در این حالت کلاس X باید abstract باشد چون Y را کامل پیادهسازی نکرده، اما کلاس XX واقعاً Y را پیادهسازی میکند.
کلاس انتزاعی میتواند فیلدهای static و متدهای static داشته باشد. میتوانید از این اعضای static با ارجاع به کلاس (مثلاً AbstractClass.staticMethod()) استفاده کنید، دقیقاً مثل هر کلاس دیگری.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/