Interface — уговор који дефинише скуп апстрактних метода које класа мора да имплементира. У Java и Kotlin интерфејси су главни механизам апстракције и полиморфизма. У Java 8+ интерфејси могу садржати default и static методе, у Kotlin — имплементације подразумевано. Према Google Android Developers (2025), интерфејси се користе у 90% Android пројеката за дефинисање слојева архитектуре — репозиторијума, UseCase и сервиса.
Главно
Interface — референтни тип који садржи апстрактне методе, константе и методе подразумевано. Класа која имплементира интерфејс мора да обезбеди имплементацију свих његових апстрактних метода. У Java интерфејс не може имати стање (поља инстанце), Kotlin се такође придржава овог ограничења, али подржава својства са акцесорима.
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 методама. Default-метода count() пружа имплементацију подразумевано која се може прегазити. UserRepositoryImpl имплементира интерфејс, користећи EntityManager за приступ подацима. Овај приступ омогућава тестирање слоја података преко mock интерфејса без праве базе података.
Избор између интерфејса и апстрактне класе зависи од постојања заједничког стања и односа између типова. Интерфејс дефинише уговор (шта класа може да ради), апстрактна класа — заједничку имплементацију (шта класа јесте).
| Критеријум | Interface | Abstract Class |
|---|---|---|
| Стање (поља) | Само static final константе | Да, било која поља |
| Конструктори | Не | Да |
| Вишеструко наслеђивање | Да (implements) | Не (extends један) |
| Модификатори приступа | public (Java 8-), default методе | Сви (private, protected, public) |
| Када користити | Уговор за неповезане класе | Заједничка основа за сродне класе |
У Clean Architecture интерфејси се налазе у унутрашњем слоју (domain), а имплементације — у спољашњем (data). Ово омогућава поштовање Правила зависности: спољашњи слој зависи од унутрашњег, али не обрнуто. Апстрактне класе се чешће користе за шаблонске методе (Template Method pattern).
Kotlin интерфејси су флексибилнији од Java: могу декларисати апстрактна својства и пружати имплементације метода. За разлику од Java, Kotlin подржава делегирање кроз кључну реч by, што значајно смањује boilerplate при имплементацији Delegate шаблона.
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 loggerUserService имплементира интерфејс Logger кроз делегирање (by). Сви позиви log() се прослеђују објекту logger без писања wrapper метода. Ово је пример композиције која би у Java захтевала 5-10 линија boilerplate кода.
Clean Architecture за Android јасно раздваја апликацију на слојеве. Интерфејси играју улогу граница између слојева: Domain дефинише интерфејсе репозиторијума и UseCase-ова, Data пружа имплементације. Ово омогућава замену имплементација без промене пословне логике — кључна предност при миграцији са Room на Firebase или са REST на GraphQL.
// 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 методе су додате у Java 8 ради еволутивног проширења интерфејса без нарушавања уназад компатибилности. Да ArrayList није имплементирао нову методу stream() додату у Collection, стари код би наставио да ради. Static методе у интерфејсима служе за алате везане за интерфејс — алтернатива класама-алатима.
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 принципа. Размотримо три честа проблема.
Интерфејс са 15+ метода крши Interface Segregation Principle (ISP). Пример — стари java.util.Dictionary са 10+ метода. Решење: поделити на неколико малих интерфејса — ReadableRepository, WritableRepository, SearchableRepository. Клијент (сервис) зависи само од метода које су му потребне.
Креирање интерфејса за сваку класу без стварне потребе за полиморфизмом је антишаблон Interface overkill. Знак: интерфејс има тачно једну имплементацију и у пројекту нема планова за додавање алтернатива. Решење: додавати интерфејс само када се појави друга верзија имплементације или потреба за mock-ом у тестовима.
Често постављана питања
Interface дефинише само уговор (сигнатуре метода), не може имати стање и подржава вишеструко наслеђивање. Abstract class може садржати поља, конструкторе и имплементиране методе, али класа може наследити само једну апстрактну класу. Од Java 8 интерфејси су добили default и static методе, смањивши разлику.
Да, у Java и Kotlin интерфејси подржавају наслеђивање. public interface AdvancedRepository<T> extends Repository<T>, Pageable — интерфејс који обједињује два друга. Класа која имплементира AdvancedRepository мора имплементирати све методе оба родитељска интерфејса. Вишеструко наслеђивање је дозвољено само за интерфејсе.
Функционални интерфејс — интерфејс са једном апстрактном методом (SAM — Single Abstract Method). Анотација @FunctionalInterface гарантује ово ограничење. Примери: Runnable, Callable, Comparator, Consumer. Функционални интерфејси су основа ламбда израза у Java 8: () -> System.out.println() имплементира Runnable.
Default методе омогућавају додавање нових метода у интерфејс без измене свих имплементирајућих класа. На пример, Java 8 је додала stream() у Collection као default-методу. Без овог механизма, foreach(), stream() и друге методе би захтевале промену хиљада класа у JDK. Default — уназад компатибилан начин проширења.
Kotlin забрањује вишеструко наслеђивање класа, али дозвољава вишеструку имплементацију интерфејса. Ако два интерфејса имају методу са истом сигнатуром и имплементацијом подразумевано, компајлер захтева експлицитно прегажење са позивом super<InterfaceName>.method(). Ово решава дијамант проблем на нивоу компајлације.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође