Interface — sinifin tətbiq etməli olduğu abstrakt metodlar toplusunu müəyyən edən kontraktdır. Java və Kotlin-də interfeyslər abstraksiya və polimorfizmin əsas mexanizmidir. Java 8+-da interfeyslər default və static metodlar ehtiva edə bilər, Kotlin-də isə standart tətbiqlər ola bilər. Google Android Developers (2025) məlumatına görə, interfeyslər Android layihələrinin 90%-də arxitektura qatlarını — repozitoriləri, UseCase və xidmətləri təyin etmək üçün istifadə olunur.
Əsas məqamlar
Interface — abstrakt metodlar, sabitlər və standart metodlar ehtiva edən istinad tipidir. İnterfeysi tətbiq edən sinif onun bütün abstrakt metodlarının tətbiqini təmin etməlidir. Java-da interfeys vəziyyətə (instansiya sahələrinə) malik ola bilməz, Kotlin də bu məhdudiyyətə riayət edir, lakin aksessorlarla xassələri dəstəkləyir.
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;
// getterlər və setterlər
}
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();
}
// qalan metodlar
}Repository<T> — CRUD metodları olan generic interfeys. Default-metod count() standart tətbiqi təmin edir, onu ləğv etmək olar. UserRepositoryImpl interfeysi tətbiq edir, məlumatlara giriş üçün EntityManager istifadə edir. Bu yanaşma real verilənlər bazası olmadan interfeysin mock vasitəsilə məlumat qatını test etməyə imkan verir.
İnterfeys və abstrakt sinif arasında seçim ümumi vəziyyətin mövcudluğundan və tiplər arasındakı münasibətlərdən asılıdır. İnterfeys kontraktı (sinifin nə edə biləcəyini), abstrakt sinif isə ümumi tətbiqi (sinifin nə olduğunu) müəyyən edir.
| Kriteriya | Interface | Abstract Class |
|---|---|---|
| Vəziyyət (sahələr) | Yalnız static final sabitlər | Bəli, istənilən sahələr |
| Konstruktorlar | Xeyr | Bəli |
| Çoxlu miras | Bəli (implements) | Xeyr (extends bir) |
| Giriş modifikatorları | public (Java 8-), default metodlar | Hamısı (private, protected, public) |
| Nə vaxt istifadə etməli | Əlaqəsiz siniflər üçün kontrakt | Qohum siniflər üçün ümumi baza |
Clean Architecture-də interfeyslər daxili qatda (domain), tətbiqlər isə xarici qatda (data) yerləşir. Bu, Asılılıq Qaydasına (Dependency Rule) riayət etməyə imkan verir: xarici qat daxili qatdan asılıdır, əksinə deyil. Abstrakt siniflər daha çox şablon metodlar üçün (Template Method pattern) istifadə olunur.
Kotlin interfeysləri Java-dan daha çevikdir: onlar abstrakt xassələr elan edə və metod tətbiqləri təmin edə bilər. Java-dan fərqli olaraq, Kotlin by açar sözü ilə deleqasiyanı dəstəkləyir və bu, Delegate nümunəsini tətbiq edərkən boilerplate-ı əhəmiyyətli dərəcədə azaldır.
interface ApiService {
val baseUrl: String // abstrakt xassə
suspend fun fetchData(): Result>
fun getEndpoint(path: String): String {
return "$baseUrl/$path" // standart tətbiq
}
}
class RetrofitApiService(
override val baseUrl: String
) : ApiService {
private val client = Retrofit.Builder()
.baseUrl(baseUrl)
.build()
override suspend fun fetchData(): Result>
{
// sorğunun icrası
}
}
// by ilə deleqasiya
interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) = println(message)
}
class UserService(logger: Logger) : Logger by loggerUserService Logger interfeysini deleqasiya (by) vasitəsilə tətbiq edir. Bütün log() çağırışları sarğı metodları yazmadan logger obyektinə yönləndirilir. Bu, Java-da 5-10 sətir boilerplate-kod tələb edəcək kompozisiya nümunəsidir.
Clean Architecture Android üçün tətbiqi aydın şəkildə qatlara ayırır. İnterfeyslər qatlar arasında sərhəd rolunu oynayır: Domain repozitorilərin və UseCase-lərin interfeyslərini təyin edir, Data tətbiqləri təmin edir. Bu, biznes məntiqini dəyişmədən tətbiqləri əvəz etməyə imkan verir — Room-dan Firebase-ə və ya REST-dən GraphQL-ə miqrasiya zamanı əsas üstünlük.
// Domain qatı — interfeys (kontrakt)
interface UserRepository {
suspend fun getUser(id: String): User
suspend fun updateUser(user: User)
}
// Domain qatı — use case (interfeysdən asılıdır)
class GetUserUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(id: String): Result {
return runCatching { repository.getUser(id) }
}
}
// Data qatı — tətbiq
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 qatında interfeys. GetUserUseCase tətbiqdən deyil, interfeysdən asılıdır. Data qatında UserRepositoryImpl interfeysi tətbiq edir, API və yerli verilənlər bazasını birləşdirir. Bu arxitektura verilənlər bazası və ya şəbəkə konfiqurasiyası olmadan UseCase-i mock-repozitori ilə test etməyə imkan verir.
Default metodlar Java 8-də geriyə uyğunluğu pozmadan interfeysləri təkamül yolu ilə genişləndirmək üçün əlavə edilmişdir. ArrayList Collection-a əlavə edilmiş yeni stream() metodunu tətbiq etməsəydi, köhnə kod işləməyə davam edərdi. İnterfeyslərdə static metodlar interfeyslə əlaqəli alətlər üçün xidmət edir — alət siniflərinə alternativ.
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();
}
// sabit
String CATEGORY = "transport";
}Default-metodlar almaz problemi (diamond problem) həll edir: əgər sinif eyni default-metoda malik iki interfeysi tətbiq edirsə, kompilyator aşkar şəkildə ləğv etməyi tələb edir. Static-metodlar interfeys adı vasitəsilə çağırılır — Vehicle.of("car"), instansiya olmadan.
İnterfeys layihələndirməsində səhvlər kövrək koda, test etmədə çətinliklərə və SOLID pozuntularına gətirib çıxarır. Üç tez-tez rast gəlinən problemi nəzərdən keçirək.
15+ metodu olan interfeys Interface Segregation Principle (ISP) prinsipini pozur. Nümunə — 10+ metodu olan köhnə java.util.Dictionary. Həll yolu: bir neçə kiçik interfeysə bölmək — ReadableRepository, WritableRepository, SearchableRepository. Müştəri (xidmət) yalnız ehtiyacı olan metodlardan asılıdır.
Polimorfizmə real ehtiyac olmadan hər sinif üçün interfeys yaratmaq Interface overkill anti-nümunəsidir. Əlamət: interfeysin düz bir tətbiqi var və layihədə alternativ əlavə etmək planı yoxdur. Həll yolu: interfeysi yalnız ikinci tətbiq variantı və ya testlər üçün mock ehtiyacı yarandıqda əlavə edin.
Tez-tez verilən suallar
Interface yalnız kontraktı (metod siqnaturalarını) müəyyən edir, vəziyyətə malik ola bilməz və çoxlu mirası dəstəkləyir. Abstract class sahələr, konstruktorlar və tətbiq olunmuş metodlar ehtiva edə bilər, lakin sinif yalnız bir abstrakt sinifdən miras ala bilər. Java 8-dən etibarən interfeyslər default və static metodlar əldə edərək fərqi azaldıb.
Bəli, Java və Kotlin-də interfeyslər mirası dəstəkləyir. public interface AdvancedRepository<T> extends Repository<T>, Pageable — iki başqa interfeysi birləşdirən interfeys. AdvancedRepository-i tətbiq edən sinif hər iki valideyn interfeysin bütün metodlarını tətbiq etməlidir. Çoxlu miras yalnız interfeyslər üçün icazəlidir.
Funksional interfeys — bir abstrakt metodu olan interfeys (SAM — Single Abstract Method). @FunctionalInterface annotasiyası bu məhdudiyyəti təmin edir. Nümunələr: Runnable, Callable, Comparator, Consumer. Funksional interfeyslər Java 8 lambda ifadələrinin əsasıdır: () -> System.out.println() Runnable-i tətbiq edir.
Default metodlar bütün tətbiq edən sinifləri dəyişmədən interfeysə yeni metodlar əlavə etməyə imkan verir. Məsələn, Java 8 Collection-a stream() metodunu default-metod kimi əlavə etdi. Bu mexanizm olmasaydı, foreach(), stream() və digər metodlar JDK-da minlərlə sinfin dəyişdirilməsini tələb edərdi. Default — geriyə uyğun genişləndirmə üsuludur.
Kotlin siniflərin çoxlu mirasını qadağan edir, lakin interfeyslərin çoxlu tətbiqinə icazə verir. Əgər iki interfeys eyni siqnatura və standart tətbiqə malik metoda sahibdirsə, kompilyator super<InterfaceName>.method() çağırışı ilə aşkar şəkildə ləğv etməyi tələb edir. Bu, almaz problemini kompilyasiya səviyyəsində həll edir.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun