Interface: ماهیت، قراردادها در Java و Kotlin برای Android

نویسنده: IT Sectr منتشر شده: 2026-02-18 زمان مطالعه: 9 دقیقه

Interface — قراردادی است که مجموعه‌ای از متدهای انتزاعی را تعریف می‌کند که یک کلاس باید پیاده‌سازی کند. در Java و Kotlin اینترفیس‌ها مکانیسم اصلی انتزاع و چندریختی هستند. در Java 8+ اینترفیس‌ها می‌توانند متدهای default و static داشته باشند، در Kotlin — پیاده‌سازی پیش‌فرض. طبق Google Android Developers (2025)، اینترفیس‌ها در 90% پروژه‌های Android برای تعریف لایه‌های معماری — مخزن‌ها، UseCase و سرویس‌ها استفاده می‌شوند.

نکات اصلی

  • Interface — نوع انتزاعی که امضای متدها را بدون پیاده‌سازی تعریف می‌کند (قبل از Java 8)
  • Implements — کلمه کلیدی که کلاس را به اینترفیس متصل می‌کند؛ کلاس می‌تواند چندین اینترفیس را پیاده‌سازی کند
  • Default method — متد با پیاده‌سازی در اینترفیس Java، در Java 8 برای سازگاری معکوس اضافه شده است
  • Kotlin interface از ویژگی‌ها با getterها و پیاده‌سازی متدها پشتیبانی می‌کند و در بسیاری از سناریوها جایگزین abstract class می‌شود
  • Markup interface — اینترفیس خالی که به عنوان برچسب استفاده می‌شود (Serializable, Cloneable, RandomAccess)

Interface در Java و Kotlin چیست؟

Interface — یک نوع ارجاعی است که شامل متدهای انتزاعی، ثابت‌ها و متدهای پیش‌فرض است. کلاسی که اینترفیس را پیاده‌سازی می‌کند موظف است پیاده‌سازی تمام متدهای انتزاعی آن را ارائه دهد. در Java اینترفیس نمی‌تواند وضعیت (فیلدهای نمونه) داشته باشد، Kotlin نیز از این محدودیت پیروی می‌کند اما ویژگی‌های با دسترسی‌کننده‌ها را پشتیبانی می‌کند.

Java
public interface Repository {
    T findById(Long id);
    List findAll();
    T save(T entity);
    void deleteById(Long id);
    
    default long count() {
        return findAll().size();
    }
}

@Entity
public class UserEntity {
    private Long id;
    private String email;
    // getterها و setterها
}

public class UserRepositoryImpl implements Repository {
    private final EntityManager em;
    
    public UserEntity findById(Long id) {
        return em.find(UserEntity.class, id);
    }
    
    public List findAll() {
        return em.createQuery("FROM UserEntity", UserEntity.class)
                .getResultList();
    }
    // سایر متدها
}

Repository<T> — یک اینترفیس generic با متدهای CRUD. متد پیش‌فرض count() یک پیاده‌سازی پیش‌فرض ارائه می‌دهد که می‌توان آن را بازنویسی کرد. UserRepositoryImpl اینترفیس را پیاده‌سازی می‌کند و از EntityManager برای دسترسی به داده‌ها استفاده می‌کند. این رویکرد امکان تست لایه داده را از طریق mock اینترفیس بدون پایگاه داده واقعی فراهم می‌کند.

Interface vs abstract class: چه زمانی کدام را انتخاب کنیم

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

معیارInterfaceAbstract Class
وضعیت (فیلدها)فقط ثابت‌های static finalبله، هر فیلدی
سازنده‌هاخیربله
وراثت چندگانهبله (implements)خیر (extends یکی)
اصلاح‌کننده‌های دسترسیpublic (Java 8-)، متدهای defaultهمه (private, protected, public)
چه زمانی استفاده شودقرارداد برای کلاس‌های نامرتبطپایه مشترک برای کلاس‌های مرتبط

در Clean Architecture اینترفیس‌ها در لایه داخلی (domain) و پیاده‌سازی‌ها در لایه خارجی (data) قرار می‌گیرند. این امکان رعایت قانون وابستگی را فراهم می‌کند: لایه خارجی به داخلی وابسته است، نه برعکس. کلاس‌های انتزاعی بیشتر برای متدهای قالبی (Template Method pattern) استفاده می‌شوند.

Interface در Kotlin: ویژگی‌ها و نمایندگان

اینترفیس‌های Kotlin انعطاف‌پذیرتر از Java هستند: می‌توانند ویژگی‌های انتزاعی اعلام کرده و پیاده‌سازی متدها را ارائه دهند. برخلاف Java، Kotlin از واگذاری از طریق کلمه کلیدی by پشتیبانی می‌کند که boilerplate را هنگام پیاده‌سازی الگوی Delegate به طور قابل توجهی کاهش می‌دهد.

Kotlin
interface ApiService {
    val baseUrl: String  // ویژگی انتزاعی
    
    suspend fun fetchData(): Result>
    
    fun getEndpoint(path: String): String {
        return "$baseUrl/$path"  // پیاده‌سازی پیش‌فرض
    }
}

class RetrofitApiService(
    override val baseUrl: String
) : ApiService {
    private val client = Retrofit.Builder()
        .baseUrl(baseUrl)
        .build()
    
    override suspend fun fetchData(): Result> {
        // پیاده‌سازی درخواست
    }
}

// واگذاری از طریق by
interface Logger {
    fun log(message: String)
}

class ConsoleLogger : Logger {
    override fun log(message: String) = println(message)
}

class UserService(logger: Logger) : Logger by logger

UserService اینترفیس Logger را از طریق واگذاری (by) پیاده‌سازی می‌کند. تمام فراخوانی‌های log() بدون نوشتن متدهای wrapper به شی logger هدایت می‌شوند. این مثالی از ترکیب است که در Java به 5-10 خط کد boilerplate نیاز داشت.

Interface در Clean Architecture Android

Clean Architecture برای Android برنامه را به وضوح به لایه‌ها تقسیم می‌کند. اینترفیس‌ها نقش مرزهای بین لایه‌ها را بازی می‌کنند: Domain اینترفیس‌های مخزن‌ها و UseCaseها را تعریف می‌کند، Data پیاده‌سازی‌ها را ارائه می‌دهد. این امکان جایگزینی پیاده‌سازی‌ها را بدون تغییر منطق تجاری فراهم می‌کند — مزیت کلیدی هنگام مهاجرت از Room به Firebase یا از REST به GraphQL.

Kotlin
// لایه Domain — اینترفیس (قرارداد)
interface UserRepository {
    suspend fun getUser(id: String): User
    suspend fun updateUser(user: User)
}

// لایه Domain — use case (وابسته به اینترفیس)
class GetUserUseCase(
    private val repository: UserRepository
) {
    suspend operator fun invoke(id: String): Result {
        return runCatching { repository.getUser(id) }
    }
}

// لایه Data — پیاده‌سازی
class UserRepositoryImpl(
    private val api: UserApi,
    private val dao: UserDao
) : UserRepository {
    override suspend fun getUser(id: String): User {
        val cached = dao.getUser(id)
        if (cached != null) return cached
        val remote = api.fetchUser(id)
        dao.insertUser(remote)
        return remote
    }
    // updateUser...
}

UserRepository — اینترفیس در لایه domain. GetUserUseCase به اینترفیس وابسته است، نه به پیاده‌سازی. UserRepositoryImpl در لایه data اینترفیس را پیاده‌سازی می‌کند و API و پایگاه داده محلی را ترکیب می‌کند. چنین معماری امکان تست UseCase را با مخزن mock بدون پیکربندی پایگاه داده یا شبکه فراهم می‌کند.

متدهای Default و static در Java 8+

متدهای default در Java 8 برای گسترش تدریجی اینترفیس‌ها بدون نقض سازگاری معکوس اضافه شدند. اگر ArrayList متد جدید stream() اضافه شده به Collection را پیاده‌سازی نمی‌کرد، کد قدیمی به کار خود ادامه می‌داد. متدهای static در اینترفیس‌ها برای ابزارهای مرتبط با اینترفیس خدمت می‌کنند — جایگزینی برای کلاس‌های ابزاری.

Java
public interface Vehicle {
    void start();
    void stop();
    
    default void honk() {
        System.out.println("Beep!");
    }
    
    static Vehicle of(String type) {
        if ("car".equals(type)) return new Car();
        return new Bicycle();
    }
    
    // ثابت
    String CATEGORY = "transport";
}

متدهای default مشکل الماس (diamond problem) را حل می‌کنند: اگر کلاسی دو اینترفیس با متد default یکسان پیاده‌سازی کند، کامپایلر بازنویسی صریح را الزامی می‌کند. متدهای static از طریق نام اینترفیس فراخوانی می‌شوند — Vehicle.of("car")، بدون نمونه.

خطاهای رایج در طراحی اینترفیس‌ها

خطاها در طراحی اینترفیس‌ها منجر به کد شکننده، دشواری تست و نقض SOLID می‌شوند. سه مشکل رایج را بررسی می‌کنیم.

Interface Pollution — تعداد زیاد متدها در یک اینترفیس

اینترفیس با 15+ متد، اصل Interface Segregation Principle (ISP) را نقض می‌کند. مثال — java.util.Dictionary قدیمی با 10+ متد. راه‌حل: تقسیم به چند اینترفیس کوچک — ReadableRepository, WritableRepository, SearchableRepository. مشتری (سرویس) فقط به متدهای مورد نیاز خود وابسته است.

انتزاع بیش از حد — اینترفیس برای هر کلاس

ایجاد اینترفیس برای هر کلاس بدون نیاز واقعی به چندریختی، ضدالگوی Interface overkill است. نشانه: اینترفیس دقیقاً یک پیاده‌سازی دارد و در پروژه برنامه‌ای برای اضافه کردن جایگزین وجود ندارد. راه‌حل: اینترفیس را فقط زمانی اضافه کنید که نسخه دوم پیاده‌سازی یا نیاز به mock برای تست ظاهر شود.

سوالات متداول

تفاوت interface با abstract class در Java چیست؟

Interface فقط قرارداد (امضای متدها) را تعریف می‌کند، نمی‌تواند وضعیت داشته باشد و از وراثت چندگانه پشتیبانی می‌کند. Abstract class می‌تواند فیلدها، سازنده‌ها و متدهای پیاده‌سازی شده داشته باشد، اما کلاس فقط می‌تواند یک کلاس انتزاعی را به ارث ببرد. از Java 8 اینترفیس‌ها متدهای default و static دریافت کردند و شکاف را کاهش دادند.

آیا اینترفیس می‌تواند اینترفیس دیگری را به ارث ببرد؟

بله، در Java و Kotlin اینترفیس‌ها از وراثت پشتیبانی می‌کنند. public interface AdvancedRepository<T> extends Repository<T>, Pageable — اینترفیسی که دو اینترفیس دیگر را ترکیب می‌کند. کلاسی که AdvancedRepository را پیاده‌سازی می‌کند باید تمام متدهای هر دو اینترفیس والد را پیاده‌سازی کند. وراثت چندگانه فقط برای اینترفیس‌ها مجاز است.

اینترفیس تابعی در Java چیست؟

اینترفیس تابعی — اینترفیسی با یک متد انتزاعی (SAM — Single Abstract Method). حاشیه‌نویسی @FunctionalInterface این محدودیت را تضمین می‌کند. مثال‌ها: Runnable, Callable, Comparator, Consumer. اینترفیس‌های تابعی اساس عبارات لامبدا در Java 8 هستند: () -> System.out.println() Runnable را پیاده‌سازی می‌کند.

چرا متدهای default در اینترفیس‌های Java لازم هستند؟

متدهای default امکان افزودن متدهای جدید به اینترفیس را بدون تغییر تمام کلاس‌های پیاده‌ساز فراهم می‌کنند. به عنوان مثال، Java 8 متد stream() را به عنوان متد default به Collection اضافه کرد. بدون این مکانیزم، foreach()، stream() و سایر متدها نیاز به تغییر هزاران کلاس در JDK داشتند. Default — روشی سازگار با عقب برای گسترش است.

Kotlin چگونه مشکل وراثت چندگانه را حل می‌کند؟

Kotlin وراثت چندگانه کلاس‌ها را ممنوع می‌کند اما پیاده‌سازی چندگانه اینترفیس‌ها را مجاز می‌کند. اگر دو اینترفیس متدی با امضای یکسان و پیاده‌سازی پیش‌فرض داشته باشند، کامپایلر بازنویسی صریح با فراخوانی super<InterfaceName>.method() را الزامی می‌کند. این مشکل الماس را در سطح کامپایل حل می‌کند.

خلاصه

  • Interface — قراردادی که متدهای قابل پیاده‌سازی را تعریف می‌کند؛ مکانیسم اصلی چندریختی در Java و Kotlin
  • Java 8+ متدهای default و static را به اینترفیس‌ها اضافه کرد و شکاف با کلاس‌های انتزاعی را کاهش داد
  • Kotlin interfaces از ویژگی‌های انتزاعی، پیاده‌سازی پیش‌فرض و واگذاری با by پشتیبانی می‌کند
  • Clean Architecture از اینترفیس‌ها به عنوان مرز بین لایه‌های Domain و Data استفاده می‌کند
  • Interface Segregation Principle تقسیم اینترفیس‌های بزرگ به اینترفیس‌های تخصصی را الزامی می‌کند
  • اینترفیس‌های تابعی (Single Abstract Method) — اساس عبارات لامبدا و Stream API
  • توصیه: اینترفیس را هنگام ظهور دومین پیاده‌سازی یا نیاز به mock برای تست اضافه کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید