ในรูปแบบ MVP ควรดูตัวอย่างวัตถุต้นแบบตามเนื้อหา UI หรือเพียงแค่ส่งเนื้อหาเหล่านี้เป็นพารามิเตอร์ไปยังผู้นำเสนอ


9

ฉันใช้รูปแบบ MVP ในแอพ android ที่ฉันกำลังพัฒนา

ฉันมีองค์ประกอบ 4 อย่าง:

  1. AddUserView ที่สามารถเพิ่มผู้ใช้ใหม่:
  2. AddUserPresenter
  3. The UserInfo (the pojo)
  4. UserInfoManager (ตรรกะ businness และผู้จัดการหน่วยเก็บข้อมูล)

คำถามของฉันคือ:

เมื่อฉันกดปุ่ม "เพิ่ม" ใน AddUserView มันควรจะได้รับเนื้อหาของ textviews ยกตัวอย่าง UserInfo ใหม่และส่งต่อไปยัง Presenter หรือ AddUserView ควรรับเนื้อหา textViews และส่งไปยัง AddUserPresenter ซึ่งอันที่จริงแล้วจะยกตัวอย่าง UserInfo และส่งต่อไปยัง UserInfoManager

คำตอบ:


8

ตามคำอธิบายของ MVP ของ Martin Fowler ( http://martinfowler.com/eaaDev/uiArchs.html )

ในส่วนมุมมองของ MVC ฟาวเลอร์พูดว่า:

องค์ประกอบแรกของ Potel คือการปฏิบัติต่อมุมมองเป็นโครงสร้างของวิดเจ็ต, วิดเจ็ตที่สอดคล้องกับการควบคุมของแบบฟอร์มและการควบคุมและลบมุมมอง / ตัวควบคุมใด ๆ ออก มุมมองของ MVP เป็นโครงสร้างของวิดเจ็ตเหล่านี้ ไม่มีพฤติกรรมใด ๆ ที่อธิบายว่าวิดเจ็ตตอบสนองต่อการโต้ตอบของผู้ใช้อย่างไร

(เหมืองเน้นความหนา)

จากผู้นำเสนอ:

ปฏิกิริยาที่ใช้งานกับผู้ใช้จะทำหน้าที่อยู่ในวัตถุผู้นำเสนอแยกต่างหาก ตัวจัดการพื้นฐานสำหรับการท่าทางของผู้ใช้ยังคงอยู่ในเครื่องมือ แต่ขนย้ายวัสดุเหล่านี้เพียงผ่านการควบคุมไปยังพรีเซนเตอร์

ผู้นำเสนอจะตัดสินใจว่าจะตอบสนองต่อเหตุการณ์อย่างไร Potel กล่าวถึงการโต้ตอบนี้เป็นหลักในแง่ของการกระทำในรูปแบบซึ่งทำโดยระบบของคำสั่งและการเลือก สิ่งที่มีประโยชน์เพื่อเน้นที่นี่คือวิธีการบรรจุการแก้ไขทั้งหมดในรูปแบบในคำสั่ง - นี่เป็นรากฐานที่ดีสำหรับการแสดงพฤติกรรมการเลิกทำ / ทำซ้ำ

(อีกครั้งเหมืองเน้นตัวหนา)

ดังนั้นตามแนวทางของพรานล่าสัตว์มุมมองของคุณไม่ควรรับผิดชอบต่อพฤติกรรมใด ๆ ที่ตอบสนองต่อเหตุการณ์ปุ่ม UserInfoซึ่งรวมถึงการสร้างตัวอย่างของ ความรับผิดชอบในการตัดสินใจสร้างวัตถุเป็นของผู้นำเสนอวิธีการที่ส่งต่อเหตุการณ์ UI

อย่างไรก็ตามหนึ่งอาจโต้แย้งว่าตัวจัดการเหตุการณ์ปุ่มของมุมมองไม่ควรรับผิดชอบต่อการส่งเนื้อหาของคุณtextViewด้วยเนื่องจากมุมมองควรส่งต่อเหตุการณ์ปุ่มไปยังผู้นำเสนอและไม่มีอะไรเพิ่มเติม

ด้วย MVP เป็นเรื่องปกติสำหรับมุมมองที่จะใช้อินเทอร์เฟซที่ผู้นำเสนอสามารถใช้เพื่อรับข้อมูลโดยตรงจากมุมมอง (ในขณะที่มั่นใจว่าผู้นำเสนอยังคงไม่เชื่อในมุมมองของตัวเอง) เนื่องจาก UserInfo เป็น POJO แบบง่ายจึงอาจใช้ได้สำหรับมุมมองที่จะแสดงให้เห็นgetterสำหรับ UserInfo ซึ่งผู้นำเสนอสามารถเลือกมุมมองจากอินเทอร์เฟซ

// 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.
    }
}

สิ่งนี้แตกต่างจากการส่งผ่านUserInfoโดยตรงไปยังมุมมองโดยใช้ตัวจัดการเหตุการณ์อย่างไร ข้อแตกต่างที่สำคัญคือผู้นำเสนอยังคงต้องรับผิดชอบต่อตรรกะในที่สุดซึ่งทำให้UserInfoวัตถุถูกสร้างขึ้น เช่นเหตุการณ์ถึงผู้นำเสนอก่อนที่จะสร้างการUserInfoอนุญาตให้ผู้นำเสนอในการตัดสินใจ

ลองนึกภาพสถานการณ์ที่คุณมีตรรกะของผู้นำเสนอที่คุณไม่ต้องการUserInfoให้สร้างขึ้นตามสถานะบางอย่างในมุมมอง ตัวอย่างเช่นหากผู้ใช้ไม่ได้ทำเครื่องหมายที่ช่องทำเครื่องหมายในมุมมองหรือคุณมีการตรวจสอบการตรวจสอบกับบางฟิลด์ที่จะเพิ่มลงใน UserInfo ซึ่งล้มเหลว - ผู้นำเสนอของคุณอาจมีการตรวจสอบเพิ่มเติมก่อนโทรGetUserInfo- เช่น

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

    public void onSomethingClicked() {            

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

ตรรกะนั้นยังคงอยู่ในผู้นำเสนอและไม่จำเป็นต้องเพิ่มลงในมุมมอง หากมุมมองรับผิดชอบต่อการโทรGetUserInfo()ก็จะต้องรับผิดชอบต่อตรรกะใด ๆ ที่เกี่ยวข้องกับการใช้งาน รูปแบบ MVP พยายามหลีกเลี่ยงสิ่งใด

ดังนั้นในขณะที่วิธีการสร้างที่UserInfoอาจมีอยู่จริงในคลาสมุมมองมันไม่เคยถูกเรียกจากคลาสมุมมองเฉพาะจากผู้นำเสนอ

แน่นอนหากการสร้างจุดUserInfoสิ้นสุดต้องการการตรวจสอบเพิ่มเติมกับเนื้อหาของวิดเจ็ตการป้อนข้อมูลของผู้ใช้ (เช่นการแปลงสตริงการตรวจสอบความถูกต้อง ฯลฯ ) จะเป็นการดีกว่าที่จะแสดงตัวรับสัญญาณแต่ละตัวสำหรับสิ่งเหล่านั้น วางภายใน Presenter - UserInfoพรีเซนเตอร์แล้วสร้างของคุณ

โดยรวมแล้วเป้าหมายหลักของคุณเกี่ยวกับการแยกระหว่างผู้นำเสนอ / มุมมองคือทำให้แน่ใจว่าคุณไม่จำเป็นต้องเขียนตรรกะในมุมมอง หากคุณเคยต้องการเพิ่มifคำสั่งด้วยเหตุผลใดก็ตาม (แม้ว่าจะเป็นifคำสั่งเกี่ยวกับสถานะของคุณสมบัติวิดเจ็ต - ตรวจสอบช่องว่างเปล่าหรือบูลีนสำหรับช่องทำเครื่องหมาย) แสดงว่าอยู่ในพรีเซนเตอร์


1
คำตอบที่ยอดเยี่ยม @BenCottrell! แต่ฉันมีอีกวิธีหนึ่ง :) เป็นวิธีที่ดีที่ตั้งชื่อวิธีการเสนอเป็นonSomethingClicked()ดังนั้นเมื่อผู้ใช้คลิกที่ "บางอย่าง" การเรียกดูpresenter.onSomethingClicked()? หรือวิธีการเสนอชื่อของฉันควรตั้งชื่อเป็นการกระทำที่ตั้งใจไว้ในกรณีของฉันaddUser()?
Rômulo.Edu

1
@regmoraes เป็นคำถามที่ดี และฉันคิดว่าคุณไฮไลต์กลิ่นเล็กน้อยในโค้ดตัวอย่างของฉัน Presenterเป็นหลักสูตรที่รับผิดชอบในการตรรกะ UI มากกว่าตรรกะโดเมนและปรับแต่งเป็นพิเศษไปViewดังนั้นแนวคิดที่ควรมีอยู่เป็นแนวคิด UI ดังนั้นวิธีการตั้งชื่อonSomethingClicked()เป็นจริงที่เหมาะสม ด้วยการเข้าใจถึงปัญหาการตั้งชื่อที่ฉันเลือกไว้ในตัวอย่างด้านบนจะไม่ได้กลิ่นที่ถูกต้อง :-)
Ben Cottrell

@ BenCottrell ขอบคุณมากสำหรับคำตอบแรก ฉันเข้าใจว่าGetUserInfoวิธีนี้ใช้ได้ในมุมมองตามที่คุณกล่าวไว้ (จะถูกเรียกจากผู้นำเสนอ) สิ่งที่เกี่ยวกับifเงื่อนไขที่เป็นไปได้ภายในGetUserInfoวิธีการ บางทีบางฟิลด์ของ UserInfo จะถูกตั้งค่าผ่านปฏิกิริยาของผู้ใช้หรือไม่ สถานการณ์:ผู้ใช้อาจเลือกช่องทำเครื่องหมายจากนั้นส่วนประกอบใหม่บางอย่าง (อาจเป็น EditText ใหม่) จะปรากฏแก่ผู้ใช้ ดังนั้นในกรณีนั้นGetUserInfoวิธีการจะมีเงื่อนไขถ้า ในสถานการณ์GetUserInfoนี้ยังคงถูกต้อง?
blackkara

1
@Blackkara พิจารณาการรักษาUserInfoเป็นรูปแบบของมุมมอง (aka "ดูรุ่น") - ในสถานการณ์สมมติว่าผมจะเพิ่มbooleanสถานะของกล่องกาและที่ว่างเปล่า / nullable รัฐของกล่องข้อความเข้าString UserInfoคุณอาจพิจารณาเปลี่ยนชื่อเป็นUserInfoViewModelถ้าช่วยในการคิดในแง่ของ POJO เป็นชั้นเรียนที่มีวัตถุประสงค์ที่แท้จริงเพียงเพื่อให้UserInfoPresenterข้อมูลการค้นหาเกี่ยวกับรัฐดู
Ben Cottrell
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.