Trong mẫu MVP, Chế độ xem có thể khởi tạo một đối tượng Mô hình dựa trên nội dung UI hay chỉ truyền các nội dung này làm tham số cho Người trình bày?


9

Tôi đang sử dụng mẫu MVP trong một ứng dụng Android mà tôi đang phát triển.

Tôi có 4 yếu tố cơ bản:

  1. AddUserView nơi người dùng mới có thể được thêm:
  2. AddUserPresenter
  3. UserInfo (pojo)
  4. UserInfoManager (trình quản lý lưu trữ và logic businness)

Câu hỏi của tôi là:

Khi tôi nhấn nút "Thêm" trong AddUserView, nó sẽ nhận được nội dung của các bản xem xét, khởi tạo một UserInfo mới và chuyển nó đến Trình dẫn. Hoặc AddUserView chỉ nên lấy nội dung textViews và chuyển chúng đến AddUserPresenter, trên thực tế sẽ khởi tạo UserInfo và chuyển nó đến UserInfoManager?

Câu trả lời:


8

Theo mô tả về MVP của Martin Fowler ( http://martinfowler.com/eaaDev/uiArchs.html )

Về phần View của MVC, Fowler nói:

Yếu tố đầu tiên của Potel là coi chế độ xem như một cấu trúc của các widget, các widget tương ứng với các điều khiển của mô hình Biểu mẫu và Điều khiển và loại bỏ mọi phân tách chế độ xem / điều khiển. Quan điểm của MVP là một cấu trúc của các vật dụng này. Nó không chứa bất kỳ hành vi nào mô tả cách các vật dụng phản ứng với tương tác của người dùng .

(Tôi nhấn mạnh đậm)

Sau đó của người trình bày:

Phản ứng tích cực đối với hành động của người dùng sống trong một đối tượng người trình bày riêng biệt. Các trình xử lý cơ bản cho các cử chỉ của người dùng vẫn tồn tại trong các tiện ích, nhưng các trình xử lý này chỉ đơn thuần chuyển quyền kiểm soát cho người trình bày .

Người trình bày sau đó quyết định cách phản ứng với sự kiện này. Potel thảo luận về sự tương tác này chủ yếu về mặt hành động trên mô hình, được thực hiện bởi một hệ thống các lệnh và lựa chọn. Một điều hữu ích cần làm nổi bật ở đây là cách tiếp cận đóng gói tất cả các chỉnh sửa cho mô hình trong một lệnh - điều này cung cấp một nền tảng tốt để cung cấp hành vi hoàn tác / làm lại.

(Một lần nữa, tôi nhấn mạnh đậm)

Vì vậy, theo hướng dẫn của Fowler, Chế độ xem của bạn không chịu trách nhiệm cho bất kỳ hành vi nào phản ứng với sự kiện nút; trong đó bao gồm việc tạo một thể hiện của UserInfo. Trách nhiệm quyết định tạo một đối tượng thuộc về phương thức Người trình bày mà sự kiện UI được chuyển tiếp.

Tuy nhiên, người ta cũng có thể lập luận rằng trình xử lý sự kiện nút của View cũng không chịu trách nhiệm truyền nội dung của bạn textView, vì Chế độ xem chỉ nên chuyển tiếp sự kiện nút vào Người thuyết trình và không có gì nữa.

Với MVP, chế độ xem phổ biến để thực hiện giao diện mà người trình bày có thể sử dụng để nhận dữ liệu trực tiếp từ chế độ xem (trong khi đảm bảo người trình bày vẫn không tin vào chế độ xem). Vì UserInfo là một POJO đơn giản, nên có thể hợp lệ cho chế độ xem để hiển thị một getter cho UserInfo mà Người trình bày có thể nhận được từ Chế độ xem qua giao diện.

// The view would implement IView
public interface IView {

    public UserInfo GetUserInfo();
}

// Presenter
public class AddUserPresenter {

    private IView addUserView;

    public void SetView(IView view) {
        addUserView = view
    }

    public void onSomethingClicked() {

        UserInfo userInfo = addUserView.GetUserInfo();
        // etc.
    }
}

Làm thế nào khác nhau để chuyển UserInfotrực tiếp vào chế độ xem bằng trình xử lý sự kiện? Sự khác biệt chính là người trình bày cuối cùng vẫn chịu trách nhiệm về logic khiến cho một UserInfođối tượng được tạo ra. tức là sự kiện đã đến với Người trình bày trước khi tạo ra UserInfo, cho phép Người trình bày đưa ra quyết định.

Hãy tưởng tượng một kịch bản mà bạn có logic của người thuyết trình nơi bạn không muốn nó UserInfođược tạo ra dựa trên một số trạng thái trong chế độ xem. Ví dụ: nếu người dùng chưa đánh dấu vào hộp kiểm trên chế độ xem hoặc bạn đã kiểm tra xác thực đối với một số trường được thêm vào UserInfo không thành công - người thuyết trình của bạn có thể chứa một kiểm tra bổ sung trước khi gọi GetUserInfo- tức là

    private boolean IsUsernameValid() {
        String username = addUserView.GetUsername();
        return (username != null && !username.isEmpty());
    }

    public void onSomethingClicked() {            

        if (IsUsernameValid()) {
            UserInfo userInfo = addUserView.GetUserInfo();
            // etc.
        }
    }

Logic đó vẫn còn bên trong người trình bày và không cần phải thêm vào chế độ xem. Nếu khung nhìn chịu trách nhiệm gọi GetUserInfo()thì nó cũng sẽ chịu trách nhiệm cho bất kỳ logic nào xung quanh việc sử dụng nó; đó là những gì mô hình MVP đang cố gắng tránh.

Vì vậy, trong khi phương thức tạo ra UserInfocó thể tồn tại về mặt vật lý trong lớp View, nó không bao giờ được gọi từ lớp View, chỉ từ Người trình bày.

Tất nhiên, nếu việc tạo UserInfokết thúc yêu cầu kiểm tra bổ sung đối với nội dung của các tiện ích nhập liệu của người dùng (ví dụ: chuyển đổi chuỗi, xác thực, v.v.), thì tốt hơn là nên hiển thị các getters riêng cho những điều đó để có thể thực hiện chuyển đổi chuỗi / xác thực đặt trong Người trình bày - và sau đó người trình bày tạo của bạn UserInfo.

Nhìn chung, mục tiêu chính của bạn liên quan đến sự tách biệt giữa Người trình bày / Chế độ xem là đảm bảo rằng bạn không bao giờ cần phải viết logic trong chế độ xem. Nếu bạn thấy mình cần thêm một ifcâu lệnh vì bất kỳ lý do gì (ngay cả khi đó là một ifcâu lệnh liên quan đến trạng thái của một thuộc tính widget - kiểm tra một hộp văn bản trống hoặc boolean cho một hộp kiểm), thì nó thuộc về người trình bày.


1
Câu trả lời tuyệt vời @BenCottrell! Nhưng tôi có một cái khác :) Có phải là một cách thực hành tốt khi đặt tên cho các phương thức của người thuyết trình là onSomethingClicked(), vì vậy khi người dùng nhấp vào "cái gì đó", View sẽ gọi presenter.onSomethingClicked()? Hoặc phương pháp người trình bày của tôi nên được đặt tên là hành động dự định, trong trường hợp của tôi addUser()?
Rômulo.Edu

1
@regmoraes Câu hỏi hay; và tôi nghĩ rằng bạn đã đánh dấu một mùi nhẹ trong mã ví dụ của tôi. Tất Presenternhiên, chịu trách nhiệm về logic UI chứ không phải logic miền và được điều chỉnh cụ thể theo View, do đó, các khái niệm nên tồn tại là các khái niệm UI, vì vậy một phương thức có tên onSomethingClicked()thực sự phù hợp. Nhìn nhận lại, việc đặt tên tôi đã chọn trong ví dụ của tôi ở trên không có mùi hoàn toàn đúng :-).
Ben Cottrell

@BenCottrell Đầu tiên cảm ơn rất nhiều vì câu trả lời tuyệt vời. Tôi hiểu, đó là hợp lệ khi có GetUserInfophương pháp này trong chế độ xem như bạn đã đề cập (sẽ được kích hoạt từ người trình bày) Còn các ifđiều kiện có thể có trong GetUserInfophương thức thì sao? Có thể một số trường của UserInfo sẽ được đặt thông qua phản ứng của người dùng? Một kịch bản: Có thể người dùng chọn một hộp kiểm sau đó một số thành phần mới (có thể là một EditText mới) sẽ hiển thị cho người dùng. Vì vậy, trong trường hợp đó, GetUserInfophương thức sẽ có nếu điều kiện. Trong kịch bản GetUserInfonày có còn hiệu lực?
blackkara

1
@Blackkara Hãy xem xét việc xử lý UserInfonhư một mô hình của chế độ xem (còn gọi là "Mô hình xem") - Trong trường hợp đó, tôi sẽ thêm booleantrạng thái của hộp kiểm và Stringtrạng thái trống / rỗng của hộp văn bản vào UserInfo. Bạn thậm chí có thể xem xét đổi tên nó thành UserInfoViewModelnếu điều đó giúp suy nghĩ về POJO là một lớp học với mục đích thực sự duy nhất là để cho phép UserInfoPresentertìm hiểu thông tin về trạng thái Xem.
Ben Cottrell
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.