Tại sao phải tạo một interface cho mỗi class?

Xin chào, các bạn giúp mình cái này với
Mình có một kho máy quạt MVC pattern
Mình có class model như sau :

public class QuạtTreoTường {
	private String loại;
	private int CôngSuất;
}

Nếu như bình thường mình sẽ cho nó behavior như sau :

public class QuạtTreoTường  {
	private String loại;
	private int CôngSuất;
	public Gió quay() {
		return Gió;
	}
	public Nước phunSương() {
		return Nước;
	}
}

Và mình sử dụng nó như sau :
QuạtTreoTường m1 = new QuạtTreoTường();

NHƯNG SAU ĐÂY LÀ CÁCH LÀM CỦA MỌI NGƯỜI

Cho nó một interface

public interface IMáyQuạt {
	Gió quay();
	Nước phunSương();
}

Cho QuạtTreoTường implement nó

public class QuạtTreoTường implements IMáyQuạt {

	private String loại;
	private int CôngSuất;
	
	@Override
	public Gió quay() {
		return Gió;
	}

	@Override
	public Nước phunSương() {
		return Nước;
	}
}

và sử dụng nó như này :
IMáyQuạt m1 = new QuạtTreoTường();

Ai cũng đều giải thích với mình 3 combo kinh điển này :
1/ Dễ bảo trì, maintain
2/ Dễ mở rộng.
3/ đúng với thiết kế theo design pattern, SOLID.

Nhưng mình vẫn chưa hiểu rõ. Mong các bạn giải thích giúp (trong trường hợp này thôi nha) Mình Cảm ơn ! :star_struck:

Bạn trả lời vài câu hỏi giúp mình:

  • Nếu bây giờ mình muốn có thêm QuạtTrần nữa thì bạn làm ntn?
  • Nếu bây giờ mình có 1 cái phòng có sẵn 1 công tắc mà chưa có quạt, thì mình làm sao mà có thể gắn loại Quạt nào vào cũng chạy được.
public class Phòng {
    // Bỏ quạt vào phòng như thế nào?
    private ... quạt = new ...();

    public void bậtQuạt() {
        quạt.quay();
    }
}

Như ví dụ này, chỉ cần gắn Quạt và gọi Phòng.bậtQuạt() thì Quạt sẽ hoạt động. Không cần biết là loại quạt gì.

Sorry ví dụ về quạt khó mô tả quá.

6 Likes

Ohm, với TH của cậu, cậu không cần dùng tới interface đâu. Cậu có mỗi class QuatTreoTuong thôi mà :smile:
Cậu chỉ cần tới interface khi cậu thiết kế 1 bài toán tổng thể, khi mà Quạt được đặt vào một ngữ cảnh sử dụng nào đó. @tonghoangvu đã đưa cho cậu một vài ngữ cảnh đó rồi! :smile:


Liên quan tới ngữ nghĩa, IMayQuat thực ra không valid đâu. Interface định nghĩa ra hành vi của đối tượng, tức là đối tượng có thể làm hành động gì đó.
Thực tế, không phải tất cả các Quạt đều có thể phun sương. Nếu cậu định nghĩa interface MáyQuạt như vậy, có nhiều khả năng một trong 2 method đó không được sử dụng/implement ở các class implement interface đó (vi phạm nguyên lý I trong SOLID rồi) :smile:
Sẽ tốt hơn nếu cậu có:

public interface Quạtable {
	Gió quay();
}

public interface MáyTạoĐộẨmable {
	Nước phunSương();
}

// Quạt này không phun sương được, nên chỉ cần implement Quạtable thôi
public class QuạtTreoTường implements Quạtable {

	private String loại;
	private int CôngSuất;
	
	@Override
	public Gió quay() {
		return Gió;
	}
}

// Quạt này xịn nè
public class QuạtTrầnSiêuXịn implements Quạtable, MáyTạoĐộẨmable {

	private String loại;
	private int CôngSuất;
	
	@Override
	public Gió quay() {
		return Gió;
	}

	@Override
	public Nước phunSương() {
		return Nước;
	}
}

// Sử dụng trong 1 ngữ cảnh trừu tượng: Phòng có thể chứa bất cứ loại quạt nào, nhưng
// nó không thực sự quan tâm quạt nào được sử dụng. Nó chỉ cần quan tâm tới
// bật một cái quạt gì đó, hoặc bật một máy tạo độ ẩm nào đó.
public class PhòngThôngMinh {
    // Bỏ quạt vào phòng như thế nào?
    private ... quạt = new ...();

    public void bậtQuạt(Quạtable quạt) {
        quạt.quay();
    }

    public void bậtMáyTạoĐộẨm(MáyTạoĐộẨmable máy) {
       máy.phunSương();
   }

   ...
   bậtQuạt(new QuạtTreoTường()); // Bật được quạt nè
   bậtMáyTạoĐộẨm(new QuạtTrầnSiêuXịn()); // Bật được máy tạo độ ẩm khi đưa quạt xịn vào nè
   bậtQuạt(new QuạtTrầnSiêuXịn()); // Bật được quạt nếu đưa quạt xịn vào nè
}

Nếu cậu không có Phòng (thứ cần mô tả 1 cách trừu tượng), thì để nguyên 1 class QuạtTreoTường sẽ dễ sử dụng hơn, và hiển nhiên cậu không cần design pattern ở đây. Đồng thời nó cũng đã SOLID rồi :smiley:

8 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?