Interface là một hợp đồng xác định tập hợp các phương thức trừu tượng mà một lớp phải triển khai. Trong Java và Kotlin, interface là cơ chế chính của sự trừu tượng và đa hình. Trong Java 8+, interface có thể chứa phương thức default và static, trong Kotlin — triển khai mặc định. Theo Google Android Developers (2025), interface được sử dụng trong 90% dự án Android để định nghĩa các tầng kiến trúc — repository, UseCase và dịch vụ.
Những điểm chính
Interface là một kiểu tham chiếu chứa các phương thức trừu tượng, hằng số và phương thức mặc định. Một lớp triển khai interface phải cung cấp triển khai cho tất cả các phương thức trừu tượng của nó. Trong Java, interface không thể có trạng thái (trường instance); Kotlin cũng tuân theo hạn chế này nhưng hỗ trợ thuộc tính với bộ truy cập.
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 và 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();
}
// các phương thức khác
}Repository<T> là một interface generic với các phương thức CRUD. Phương thức default count() cung cấp triển khai mặc định có thể được ghi đè. UserRepositoryImpl triển khai interface sử dụng EntityManager để truy cập dữ liệu. Cách tiếp cận này cho phép kiểm thử tầng dữ liệu thông qua mock của interface mà không cần cơ sở dữ liệu thực.
Lựa chọn giữa interface và lớp trừu tượng phụ thuộc vào sự hiện diện của trạng thái chia sẻ và mối quan hệ giữa các kiểu. Interface định nghĩa một hợp đồng (lớp có thể làm gì), lớp trừu tượng định nghĩa một triển khai chung (lớp là gì).
| Tiêu chí | Interface | Abstract Class |
|---|---|---|
| Trạng thái (trường) | Chỉ hằng số static final | Có, bất kỳ trường nào |
| Hàm tạo | Không | Có |
| Đa kế thừa | Có (implements) | Không (extends một) |
| Bổ từ truy cập | public (Java 8-), phương thức default | Tất cả (private, protected, public) |
| Khi nào sử dụng | Hợp đồng cho các lớp không liên quan | Cơ sở chung cho các lớp liên quan |
Trong Clean Architecture, interface được đặt ở tầng bên trong (domain), và triển khai ở tầng bên ngoài (data). Điều này cho phép duy trì Dependency Rule: tầng ngoài phụ thuộc vào tầng trong, nhưng không ngược lại. Lớp trừu tượng thường được sử dụng cho các phương thức khuôn mẫu (Template Method pattern).
Interface Kotlin linh hoạt hơn Java: chúng có thể khai báo thuộc tính trừu tượng và cung cấp triển khai phương thức. Không giống Java, Kotlin hỗ trợ ủy quyền qua từ khóa by, giúp giảm đáng kể boilerplate khi triển khai mẫu Delegate.
interface ApiService {
val baseUrl: String // thuộc tính trừu tượng
suspend fun fetchData(): Result>
fun getEndpoint(path: String): String {
return "$baseUrl/$path" // triển khai mặc định
}
}
class RetrofitApiService(
override val baseUrl: String
) : ApiService {
private val client = Retrofit.Builder()
.baseUrl(baseUrl)
.build()
override suspend fun fetchData(): Result>
{
// triển khai yêu cầu
}
}
// Ủy quyền qua by
interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) = println(message)
}
class UserService(logger: Logger) : Logger by loggerUserService triển khai interface Logger thông qua ủy quyền (by). Tất cả các cuộc gọi log() được chuyển tiếp đến đối tượng logger mà không cần viết phương thức bao. Đây là một ví dụ về hợp thành mà trong Java sẽ cần 5-10 dòng mã boilerplate.
Clean Architecture cho Android phân chia ứng dụng rõ ràng thành các tầng. Interface đóng vai trò là ranh giới giữa các tầng: Domain định nghĩa interface repository và UseCase, Data cung cấp triển khai. Điều này cho phép thay thế triển khai mà không thay đổi logic nghiệp vụ — một lợi thế chính khi di chuyển từ Room sang Firebase hoặc từ REST sang GraphQL.
// Domain layer — interface (hợp đồng)
interface UserRepository {
suspend fun getUser(id: String): User
suspend fun updateUser(user: User)
}
// Domain layer — use case (phụ thuộc vào interface)
class GetUserUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(id: String): Result {
return runCatching { repository.getUser(id) }
}
}
// Data layer — triển khai
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 là một interface trong tầng domain. GetUserUseCase phụ thuộc vào interface, không phải triển khai. UserRepositoryImpl trong tầng data triển khai interface, kết hợp API và cơ sở dữ liệu cục bộ. Kiến trúc này cho phép kiểm thử UseCases với repository mock mà không cần thiết lập cơ sở dữ liệu hoặc mạng.
Phương thức default được thêm vào Java 8 để mở rộng tiến hóa của interface mà không phá vỡ tương thích ngược. Nếu ArrayList không triển khai phương thức stream() mới được thêm vào Collection, mã cũ vẫn tiếp tục hoạt động. Phương thức static trong interface phục vụ như các tiện ích liên quan đến interface — một giải pháp thay thế cho các lớp tiện ích.
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();
}
// hằng số
String CATEGORY = "transport";
}Phương thức default giải quyết vấn đề kim cương: nếu một lớp triển khai hai interface có cùng phương thức default, trình biên dịch yêu cầu ghi đè rõ ràng. Phương thức static được gọi thông qua tên interface — Vehicle.of("car"), mà không cần instance.
Lỗi trong thiết kế interface dẫn đến mã dễ vỡ, phức tạp kiểm thử và vi phạm SOLID. Hãy xem xét ba vấn đề phổ biến.
Interface chứa 15+ phương thức vi phạm Interface Segregation Principle (ISP). Một ví dụ là java.util.Dictionary cũ với 10+ phương thức. Giải pháp: chia thành nhiều interface nhỏ — ReadableRepository, WritableRepository, SearchableRepository. Client (dịch vụ) chỉ phụ thuộc vào các phương thức nó cần.
Tạo interface cho mọi lớp mà không có nhu cầu thực sự về đa hình là phản mẫu Interface overkill. Dấu hiệu: interface có đúng một triển khai và dự án không có kế hoạch thêm giải pháp thay thế. Giải pháp: chỉ thêm interface khi xuất hiện tùy chọn triển khai thứ hai hoặc cần mock cho kiểm thử.
Câu hỏi thường gặp
Interface chỉ định nghĩa hợp đồng (chữ ký phương thức), không thể có trạng thái và hỗ trợ đa kế thừa. Abstract class có thể chứa trường, hàm tạo và phương thức đã triển khai, nhưng một lớp chỉ có thể kế thừa một lớp trừu tượng. Từ Java 8, interface đã có phương thức default và static, thu hẹp khoảng cách.
Có, trong Java và Kotlin, interface hỗ trợ kế thừa. public interface AdvancedRepository<T> extends Repository<T>, Pageable là một interface kết hợp hai interface khác. Lớp triển khai AdvancedRepository phải triển khai tất cả phương thức của cả hai interface cha. Đa kế thừa chỉ được phép cho interface.
Interface hàm là interface có một phương thức trừu tượng duy nhất (SAM — Single Abstract Method). Chú thích @FunctionalInterface đảm bảo hạn chế này. Ví dụ: Runnable, Callable, Comparator, Consumer. Interface hàm là nền tảng của biểu thức lambda Java 8: () -> System.out.println() triển khai Runnable.
Phương thức default cho phép thêm phương thức mới vào interface mà không sửa đổi tất cả các lớp triển khai. Ví dụ, Java 8 đã thêm stream() vào Collection như một phương thức default. Nếu không có cơ chế này, foreach(), stream() và các phương thức khác sẽ yêu cầu thay đổi hàng nghìn lớp trong JDK. Default là cách mở rộng tương thích ngược.
Kotlin cấm đa kế thừa lớp nhưng cho phép triển khai nhiều interface. Nếu hai interface có phương thức cùng chữ ký và triển khai mặc định, trình biên dịch yêu cầu ghi đè rõ ràng với lời gọi super<InterfaceName>.method(). Điều này giải quyết vấn đề kim cương ở cấp độ biên dịch.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm