[Java] Sử dụng interface

Có rất nhiều vấn đề đật ra như interface dùng để làm gì, tại sao dùng interface, dùng interface như thế nào,… Trong bài này mình hy vọng có thể trả lời phần nào đó một cách dễ hiểu nhất có thể vì thông thường nó tương đối trừu tượng =)) và cũng nói luôn là những điều viết dưới đây nằm trong khuôn khổ hiểu biết hạn chế của mình, nếu bạn có thể bổ xung điều gì đó thì thực sự là tuyệt với đối với mình cũng như bạn đọc theo dõi.

1. Sử dụng Interface tạo hành động chung cho đối tượng

Lấy ví dụ luôn nhé. Tưởng tượng rằng hàng ngày bạn học rất nhiều môn, như Toán, Lý, Hóa, Sinh, Anh, Văn, Sử,… mỗi môn một quyển sách hoặc vở, như vậy thật bất tiện khi bạn “soạn sách” tới lớp. Bây giờ mình bày cho bạn một cách mà không cần biết hôm nay học môn gì mà vẫn có sách của môn đó khi đến lớp, đó là sử dụng sách đa năng mà có thể chứa mọi môn học của bạn. Chính mình cũng đang làm cách đó bằng cách cho mọi môn vào 1 cuốn sổ đa năng, đi học chỉ cầm duy nhất nó đi là xong =)).

Trong lập trình thì cuốn sách (sổ) đa năng đó chính là interface của bạn. Bây giờ hãy bắt đầu dùng thử nhé. Bạn có các môn Toán, Lý, Hóa, Sinh,.. như mình vừa nêu, mỗi môn là một class. Bạn có một mảng các cuốn sách đó và cần mang tới trường và chúng ta thử xem bình thường ta làm thế nào?

package cachhoc.net.useinterface.method;

class Toan {
	public void mangSachToiTruong() {
		System.out.println("Sach Toan duoc mang toi truong");
	}
}

class Ly {
	public void mangSachToiTruong() {
		System.out.println("Sach Ly nhe");
	}
}

class Hoa {
	public void mangSachToiTruong() {
		System.out.println("Sach Hoa ok");
	}
}

class Sinh {
	public void mangSachToiTruong() {
		System.out.println("Sach Sinh day roi");
	}
}

public class TruongHoc {
	public static void main(String[] args) {
		Object[] sach = { new Toan(), new Ly(), new Hoa(), new Sinh() };
		for (Object s : sach) {
			s.mangSachToiTruong(); // loi roi nhe
		}
	}
}

Bạn thử code đi, bạn sẽ thấy là để tạo ra được mảng sach chúng ta không còn cách nào khác là đặt nó là mảng Object và khi gọi các phương thức mangSachToiTruong() sẽ không thực hiện được.

Bây giờ interface sẽ giúp chúng ta giải quyết vấn đề này. Trước tiên chúng ta tạo một interface Sach có phương thức là mangSachToiTruong();

package cachhoc.net.useinterface.method;

public interface Sach {
	public void mangSachToiTruong();
}

Sau đó chúng ta tạo ra các class Toan, Ly, Hoa, Sinh implements Sach và thực thi phương thức mangSachToiTruong và vấn đề được giải quyết như sau.

package cachhoc.net.useinterface.method;

class Toan implements Sach {
	@Override
	public void mangSachToiTruong() {
		System.out.println("Sach Toan duoc mang toi truong");
	}
}

class Ly implements Sach {
	@Override
	public void mangSachToiTruong() {
		System.out.println("Sach Ly nhe");
	}
}

class Hoa implements Sach {
	@Override
	public void mangSachToiTruong() {
		System.out.println("Sach Hoa ok");
	}
}

class Sinh implements Sach {
	@Override
	public void mangSachToiTruong() {
		System.out.println("Sach Sinh day roi");
	}
}

public class TruongHoc {
	public static void main(String[] args) {
		Sach[] sach = { new Toan(), new Ly(), new Hoa(), new Sinh() };
		for (Sach s : sach) {
			s.mangSachToiTruong();
		}
	}
}

2. Truyền nhận dữ liệu, thông điệp giữa các class

Người ta thường nói là các class trao đổi dữ liệu, thông điệp qua interface. Trong phần này chúng ta sẽ tìm hiểu nó. Vấn đề này sẽ được rõ ràng hơn nếu như chúng ta làm trên giao diện, tức là sử dụng các JFrame. Nhưng nếu bạn chưa làm với giao diện cũng không sao.

Bạn có 2 class là GiaoDien và Download. class GiaoDien có một nút, khi click vào nút thì gọi phương thức download nằm trong class Download để download file, và trong quá trình download, class download phải phản hồi lại cho class GiaoDien biết là download được bao nhiêu phần trăm rồi. Bạn hãy xem 2 cách làm dưới đây của mình nhé.

Cách 1 (Cách cùi bắp ngày xưa hay dùng): Truyền đối tượng Giao diện cho class Download để cập nhập phần trăm đã download.

package cachhoc.net.useinterface.senddata;

public class GiaoDien {
	private Download download;

	/**
	 * phuong thuc khoi tao Giao dien, dong thoi khoi tao doi tuong download va
	 * truyen chinh giao dien sang class Download de cap nhat giao dien
	 */
	public GiaoDien() {
		download = new Download(this);
	}

	private void nhanDownload() {
		download.download();
	}

	public void capNhatGiaoDien(int phanTramDownload) {
		System.out.println("class giao dien cap nhat duoc: " + phanTramDownload
				+ "%");
	}

	public static void main(String[] args) {
		GiaoDien giaoDien = new GiaoDien();
		giaoDien.nhanDownload();
	}
}
package cachhoc.net.useinterface.senddata;

public class Download {
	private GiaoDien giaoDien;

	/**
	 * @param giaoDien
	 *            de cap nhat giao dien
	 */
	public Download(GiaoDien giaoDien) {
		this.giaoDien = giaoDien;
	}

	public void download() {
		for (int i = 0; i < 100; i++) {
			System.out.println("Dang download...");
			giaoDien.capNhatGiaoDien(i);
		}
		System.out.println("Ket thuc download");
	}
}

Như các bạn đã thấy thì việc cập nhật giao diện tỏ ra đơn giản khi mà chúng ta chỉ cần truyền chính đối tượng giao diện sang class Download là xong.
Tuy nhiên nhiều vấn đề xảy ra khi mà đối tượng giaoDien được truyền sang, class download được phép gọi một số phương thức của class GiaoDien mà nó không cần, phương thức cập nhật giao diện bắt buộc phải cho phép gọi ở class Download thì mới có thể gọi được mà ở đây mình để là public chứ không thể là private. Hoặc giả sử như class chúng ta phải thông qua một class X nào đó ở giữa thì phương thức download của class Download mới được gọi đến và như vậy chúng ta phải truyền GiaoDien sang X, rồi X truyền sang Download, như vậy rất phức tạp… và rất nhiều hạn chế khác mà khi bạn làm thực tế sẽ hiểu rõ hơn.

Cách 2: Sử dụng Interface

Chúng ta tạo thêm một interface tên là CapNhat có chứa phương thức capNhatGiaoDien(); sau đó cho GiaoDien implements CapNhat như sau:

package cachhoc.net.useinterface.senddata;

public interface CapNhat {
	public void capNhatGiaoDien(int giaTri);
}
package cachhoc.net.useinterface.senddata;

public class Download {
	private CapNhat capNhat;

	/**
	 * @param capNhat
	 *            lang nghe su kien download
	 */
	public void addDownloadListener(CapNhat capNhat) {
		this.capNhat = capNhat;
	}

	public void download() {
		for (int i = 0; i < 100; i++) {
			System.out.println("Dang download...");

			/**
			 * Khi goi capNhat.capNhatGiaoDien(i); thi phuong thuc nay se tu
			 * dong duoc goi trong giao dien
			 * */

			capNhat.capNhatGiaoDien(i);
		}
		System.out.println("Ket thuc download");
	}
}
package cachhoc.net.useinterface.senddata;

public class GiaoDien implements CapNhat {
	private Download download;

	/**
	 * phuong thuc khoi tao Giao dien, dong thoi dat lang nghe su kien download
	 */
	public GiaoDien() {
		download = new Download();

		/** dat lang nghe su kien download */
		download.addDownloadListener(this);
	}

	private void nhanDownload() {
		download.download();
	}

	/**
	 * Tu dong duoc goi trong qua trinh download thong qua interface CapNhap
	 */
	@Override
	public void capNhatGiaoDien(int giaTri) {
		System.out.println("class giao dien cap nhat duoc: " + giaTri + "%");
	}

	public static void main(String[] args) {
		GiaoDien giaoDien = new GiaoDien();
		giaoDien.nhanDownload();
	}
}

Các bạn có thể thấy rằng cách 2 này khắc phục được các nhược điển của cách 1. Class download không hề cần truyền đối tượng GiaoDien mà chỉ cần một interface CapNhat, do đó các phương thức, thuốc tính của GiaoDien không “bị lộ” hay có thể được gọi bên Download. Nếu phải thông qua một class X nào đó rồi download mới được thực hiện thì cũng không cần truyền đối tượng GiaoDien qua những class trung gian đó mà vẫn cập nhật được giao diện trong quá trình download. Hoặc giả sử có nhiều giao diện cần được cập nhật trong quá trình download thì đó là điều vô tư khi mà với cách 1 thì sẽ khó khăn hơn nhiều vì cần truyền mọi giao diện đó vào class Download…

Trên đây là 2 ứng dụng sử dụng Interface mà mình thấy rõ nhất. Rất mong nó có thể giúp ích gì đó cho bạn trong quá trình tìm hiểu cách dùng interface.

Nguồn bài viết tại cachhoc.net