Làm cách nào để cấu trúc các giao diện khi các đối tượng chỉ sử dụng một phần của giao diện?


9

Tôi có một dự án trong đó tôi có hai lớp yêu cầu một đối tượng truy cập cơ sở dữ liệu cập nhật cùng một bảng. Các ràng buộc của khung và dự án làm cho nó để tôi không thể kết hợp hai lớp này. Tôi đã tạo ra một trường hợp dưới đây cho thấy cách thiết lập. Lớp A cần có khả năng cập nhật và đọc bản ghi, trong khi lớp B cần có khả năng cập nhật và xóa bản ghi.

Nếu tôi sử dụng các lớp như hiện tại, nó hoạt động tốt, nhưng tôi gặp vấn đề với thực tế là mỗi lớp đều yêu cầu chức năng mà nó không sử dụng để thực hiện. Ví dụ, để sử dụng lớp A, tôi phải truyền cho nó một dao thực hiện chức năng xóa, mặc dù nó sẽ không bao giờ được gọi. Tương tự, tôi phải vượt qua lớp B a dao thực hiện chức năng đọc nhưng nó sẽ không bao giờ được gọi.

Tôi đã nghĩ đến việc tiếp cận nó bằng cách có các giao diện kế thừa các giao diện khác (IReadDao, IUpdateDao, IDeleteDao là các dao sẽ được kế thừa từ đó), nhưng về cơ bản, cách tiếp cận này sẽ yêu cầu một giao diện khác nhau cho mỗi tổ hợp chức năng (IUpdateAndRead, IReadAndDead, IReadAndDead )

Tôi muốn sử dụng giao diện cho dao vì tôi không muốn ghép ứng dụng với cơ sở dữ liệu. Có một mô hình hoặc phương pháp để thực hiện những gì tôi muốn mà bất cứ ai biết về? Cảm ơn trước.

class IDao {

  void update(ModelDao model);
  void delete(String guid);
  ModelDao read(String guid);

}

Class A {

  private IDao dao;

  public A(IDao dao) {

    this.dao = dao;

  }

  public void doStuff() {

    ModelDao model = new ModelDao();

    ...

    dao.update(model);

  }

  public void readThenDoSomething(String id) {

    ModelDao model = dao.read(id);

    ...

  }

}

Class B {

  private IDao dao;

  public B(IDao dao) {

    this.dao = dao;

  }

  public void makeUpdate() {

    ModelDao model = new ModelDao();

    ...

    dao.update(model);

  }

  public void delete(String id) {

    dao.delete(id);

  }

}

2
Tại sao bạn cần các giao diện riêng biệt cho mỗi kết hợp thay vì chỉ có mỗi lớp sử dụng chúng thực hiện những giao diện chúng cần?
yitzih

Trong trường hợp trên, thay vì chuyển IDao cho hàm tạo của A, tôi sẽ phải truyền một đối tượng thực hiện IUpdate và IRead, vậy loại biến "dụ" sẽ là gì? Nó sẽ không phải là một cái gì đó giống như IUpdateAndReadDao? Nó vẫn cần phải là một giao diện bởi vì nếu tôi bảo nó thực hiện một cơ sở dữ liệu cụ thể thì tôi đã ghép lớp với db. Có phải đó là những gì bạn đã được hỏi?
jteezy14

3
Tôi nghĩ rằng đây là một ví dụ hoàn hảo về Nguyên tắc phân chia giao diện ( Itừ SOLID). Có thể muốn đọc một chút về nó.
Christopher Francisco

Câu trả lời:


10

Theo nhận xét của Christopher, có lẽ tốt hơn một chút để phân tách các giao diện . Vì vậy, bạn sẽ cần ít nhất IReadDao, IDeleteDaoIUpdateDao. Lưu ý rằng bạn không nhất thiết cần ba lớp; bạn có thể có một lớp DAO lớn thực hiện cả ba giao diện, nếu nó hợp lý với cơ sở mã được kết hợp theo cách đó.

Để tránh sự bùng nổ tổ hợp (ví dụ như để tránh sự cần thiết cho một IReadUpdate, IDeleteUpdatevv giao diện), bạn có thể cung cấp các giao diện riêng trong constructor injection (bạn có thể vượt qua cùng một đối tượng gấp đôi so với các thông số khác nhau), hoặc cung cấp một đối tượng duy nhất hỗ trợ hai hoặc nhiều giao diện trong một cuộc gọi phương thức chung sử dụng extends.

Xây dựng tiêm:

class MyDaoLibrary : IUpdateDao, IInsertDao, IDeleteDao {
    //Etc....
}

class A
{
    //It is OK if the IoC container factory provides the same instance for both parameters.
    a(IUpdateDao dao1, IDeleteDao dao2) {
        this.updater = dao1;
        this.deleter = dao2;
    }
    //Etc....
}

Tiêm Setter, sử dụng phương pháp chung:

<T extends IUpdateDao & IDeleteDao> void InitializeDao(T dao)  //Pass a single object that implements both IUpdateDao and IDeleteDao

Khi sử dụng setter tiêm, tôi sẽ khai báo biến thể hiện mà tôi đang thiết lập trong hàm InitializeDao như thế nào?
jteezy14

Bạn sẽ cần hai biến đối tượng (một biến để xóa, một biến để cập nhật) ... gán daocho cả hai.
John Wu

Ồ vâng, điều đó có ý nghĩa. Cảm ơn rất nhiều vì câu trả lời tuyệt vời!
jteezy14
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.