Interface — ay isang kontrata na tumutukoy sa isang set ng abstract na mga pamamaraan na dapat ipatupad ng isang klase. Sa Java at Kotlin, ang mga interface ay ang pangunahing mekanismo ng abstraction at polymorphism. Sa Java 8+ ang mga interface ay maaaring maglaman ng default at static na mga pamamaraan, sa Kotlin — mga default na implementasyon. Ayon sa Google Android Developers (2025), ang mga interface ay ginagamit sa 90% ng Android na mga proyekto para sa pagtukoy ng mga layer ng arkitektura — mga repositoryo, UseCase, at serbisyo.
Mga Pangunahing Punto
Interface — ay isang uri ng sanggunian na naglalaman ng abstract na mga pamamaraan, mga constant, at mga default na pamamaraan. Ang klase na nagpapatupad ng interface ay obligadong magbigay ng implementasyon ng lahat ng abstract na pamamaraan nito. Sa Java, ang interface ay hindi maaaring magkaroon ng estado (mga field ng instance), ang Kotlin ay sumusunod din sa paghihigpit na ito, ngunit sumusuporta ng mga property na may aksesor.
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 at 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();
}
// iba pang pamamaraan
}Repository<T> — isang generic na interface na may CRUD na mga pamamaraan. Ang default na pamamaraan count() ay nagbibigay ng default na implementasyon na maaaring override. Ang UserRepositoryImpl ay nagpapatupad ng interface, gamit ang EntityManager para sa pag-access ng datos. Ang ganitong paraan ay nagpapahintulot sa pagsubok ng layer ng datos sa pamamagitan ng mock ng interface nang walang tunay na database.
Ang pagpili sa pagitan ng interface at abstract na klase ay nakadepende sa pagkakaroon ng karaniwang estado at mga relasyon sa pagitan ng mga uri. Tinutukoy ng interface ang isang kontrata (kung ano ang magagawa ng klase), ang abstract na klase — isang karaniwang implementasyon (kung ano ang klase).
| Kriterya | Interface | Abstract Class |
|---|---|---|
| Estado (mga field) | Static final constant lamang | Oo, anumang mga field |
| Mga Constructor | Hindi | Oo |
| Maramihang pamana | Oo (implements) | Hindi (extends isa) |
| Mga modifier ng access | public (Java 8-), default na mga pamamaraan | Lahat (private, protected, public) |
| Kailan gagamitin | Kontrata para sa hindi magkakaugnay na mga klase | Karaniwang batayan para sa magkakaugnay na mga klase |
Sa Clean Architecture, ang mga interface ay inilalagay sa panloob na layer (domain), at ang mga implementasyon — sa panlabas na layer (data). Ito ay nagpapahintulot sa pagsunod sa Dependency Rule: ang panlabas na layer ay nakadepende sa panloob, hindi ang kabaligtaran. Ang abstract na mga klase ay mas madalas na ginagamit para sa template na mga pamamaraan (Template Method pattern).
Ang mga interface ng Kotlin ay mas flexible kaysa sa Java: maaari silang magdeklara ng abstract na mga property at magbigay ng mga implementasyon ng pamamaraan. Hindi tulad ng Java, sinusuporta ng Kotlin ang delegasyon sa pamamagitan ng keyword na by, na makabuluhang nagbabawas ng boilerplate kapag nagpapatupad ng pattern ng Delegate.
interface ApiService {
val baseUrl: String // abstract na property
suspend fun fetchData(): Result>
fun getEndpoint(path: String): String {
return "$baseUrl/$path" // default na implementasyon
}
}
class RetrofitApiService(
override val baseUrl: String
) : ApiService {
private val client = Retrofit.Builder()
.baseUrl(baseUrl)
.build()
override suspend fun fetchData(): Result>
{
// implementasyon ng kahilingan
}
}
// Delegasyon sa pamamagitan ng by
interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) = println(message)
}
class UserService(logger: Logger) : Logger by loggerUserService ay nagpapatupad ng Logger interface sa pamamagitan ng delegasyon (by). Lahat ng tawag na log() ay ire-redirect sa logger object nang hindi nagsusulat ng wrapper na mga pamamaraan. Ito ay isang halimbawa ng komposisyon na sa Java ay mangangailangan ng 5-10 linya ng boilerplate code.
Clean Architecture para sa Android ay malinaw na hinahati ang aplikasyon sa mga layer. Ang mga interface ay gumaganap bilang hangganan sa pagitan ng mga layer: ang Domain ay tumutukoy sa mga interface ng repositoryo at UseCase, ang Data ay nagbibigay ng mga implementasyon. Ito ay nagpapahintulot sa pagpapalit ng mga implementasyon nang hindi binabago ang lohika ng negosyo — pangunahing bentahe kapag lumilipat mula Room patungong Firebase o mula REST patungong GraphQL.
// Domain layer — interface (kontrata)
interface UserRepository {
suspend fun getUser(id: String): User
suspend fun updateUser(user: User)
}
// Domain layer — use case (nakadepende sa interface)
class GetUserUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(id: String): Result {
return runCatching { repository.getUser(id) }
}
}
// Data layer — implementasyon
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 — interface sa domain layer. Ang GetUserUseCase ay nakadepende sa interface, hindi sa implementasyon. Ang UserRepositoryImpl sa data layer ay nagpapatupad ng interface, pinagsasama ang API at lokal na database. Ang ganitong arkitektura ay nagpapahintulot sa pagsubok ng UseCase sa mock-repositoryo nang walang konpigurasyon ng database o network.
Ang mga default na pamamaraan ay idinagdag sa Java 8 para sa ebolusyonaryong pagpapalawak ng mga interface nang hindi lumalabag sa backward compatibility. Kung hindi ipinatupad ng ArrayList ang bagong stream() na pamamaraan na idinagdag sa Collection, ang lumang code ay patuloy na gagana. Ang mga static na pamamaraan sa mga interface ay nagsisilbi para sa mga utility na nauugnay sa interface — alternatibo sa mga utility class.
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();
}
// constant
String CATEGORY = "transport";
}Ang mga default na pamamaraan ay lumulutas ng diamond problem: kung ang isang klase ay nagpapatupad ng dalawang interface na may parehong default na pamamaraan, ang compiler ay nangangailangan ng eksplisitong override. Ang mga static na pamamaraan ay tinatawag sa pamamagitan ng pangalan ng interface — Vehicle.of("car"), walang instance.
Ang mga pagkakamali sa pagdidisenyo ng interface ay humahantong sa marupok na code, kahirapan sa pagsubok, at paglabag sa SOLID. Suriin natin ang tatlong madalas na problema.
Ang isang interface na may 15+ pamamaraan ay lumalabag sa Interface Segregation Principle (ISP). Halimbawa — ang lumang java.util.Dictionary na may 10+ pamamaraan. Solusyon: hatiin sa maraming maliliit na interface — ReadableRepository, WritableRepository, SearchableRepository. Ang kliyente (serbisyo) ay nakadepende lamang sa mga pamamaraan na kailangan nito.
Ang paggawa ng interface para sa bawat klase nang walang tunay na pangangailangan para sa polymorphism ay anti-pattern na Interface overkill. Palatandaan: ang interface ay may eksaktong isang implementasyon at walang plano sa proyekto na magdagdag ng alternatibo. Solusyon: magdagdag ng interface lamang kapag lumitaw ang pangalawang baryante ng implementasyon o pangangailangan para sa mock para sa mga pagsubok.
Mga Madalas Itanong
Interface ay tumutukoy lamang ng kontrata (mga lagda ng pamamaraan), hindi maaaring magkaroon ng estado, at sumusuporta ng maramihang pamana. Abstract class ay maaaring maglaman ng mga field, constructor, at ipinatupad na mga pamamaraan, ngunit ang isang klase ay maaari lamang magmana ng isang abstract na klase. Mula noong Java 8, ang mga interface ay nakakuha ng default at static na mga pamamaraan, pinaliit ang agwat.
Oo, sa Java at Kotlin ang mga interface ay sumusuporta ng pamana. public interface AdvancedRepository<T> extends Repository<T>, Pageable — isang interface na pinagsasama ang dalawang iba pa. Ang klase na nagpapatupad ng AdvancedRepository ay dapat magpatupad ng lahat ng pamamaraan ng parehong magulang na interface. Ang maramihang pamana ay pinapayagan lamang para sa mga interface.
Functional interface — isang interface na may isang abstract na pamamaraan (SAM — Single Abstract Method). Ang anotasyong @FunctionalInterface ay ginagarantiyahan ang paghihigpit na ito. Mga halimbawa: Runnable, Callable, Comparator, Consumer. Ang mga functional interface ay batayan ng lambda expression sa Java 8: () -> System.out.println() ay nagpapatupad ng Runnable.
Ang mga default na pamamaraan ay nagpapahintulot sa pagdagdag ng bagong pamamaraan sa interface nang hindi binabago ang lahat ng nagpapatupad na klase. Halimbawa, idinagdag ng Java 8 ang stream() sa Collection bilang default na pamamaraan. Kung wala ang mekanismong ito, ang foreach(), stream(), at iba pang pamamaraan ay mangangailangan ng pagbabago ng libu-libong klase sa JDK. Default — isang backward compatible na paraan ng pagpapalawak.
Kotlin ay nagbabawal ng maramihang pamana ng mga klase, ngunit pinapayagan ang maramihang implementasyon ng mga interface. Kung ang dalawang interface ay may pamamaraan na may parehong lagda at default na implementasyon, ang compiler ay nangangailangan ng eksplisitong override na may tawag na super<InterfaceName>.method(). Ito ay lumulutas ng diamond problem sa antas ng compilation.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din