รูปแบบการแยกส่วนที่พบบ่อย

ไม่มีกลยุทธ์การแยกโมดูลเดียวที่เหมาะกับทุกโปรเจ็กต์ เนื่องจาก ลักษณะที่ยืดหยุ่นของ Gradle มี 2-3 ข้อจำกัดเกี่ยวกับวิธีการที่คุณสามารถ จัดโครงการ หน้านี้จะแสดงภาพรวมของกฎทั่วไปบางส่วนและกฎทั่วไป รูปแบบที่คุณสามารถใช้เมื่อพัฒนาแอป Android แบบหลายโมดูล

หลักการสำหรับการเชื่อมต่อแบบสม่ำเสมอสูงและต่ำ

วิธีหนึ่งในการกำหนดลักษณะของโค้ดเบสแบบโมดูลคือการใช้ตัวคู่ต่อ และความสอดคล้องกันได้ ตัวคู่ต่อวัดระดับของโมดูล ที่พึ่งพาซึ่งกันและกัน ความสอดคล้องกันในบริบทนี้จะวัดวิธีที่องค์ประกอบของ โมดูลเดียวมีฟังก์ชันการทำงานเกี่ยวข้องกัน ตามกฎทั่วไป คุณควรพยายาม การเชื่อมต่อแบบต่ำและการทำงานร่วมกันสูง:

  • การเชื่อมต่อแบบต่ำหมายความว่าโมดูลควรมีความเป็นอิสระมากที่สุดจาก ซึ่งกันและกัน เพื่อให้การเปลี่ยนแปลงไปยังโมดูลหนึ่งมีผลกระทบเป็นศูนย์หรือน้อยที่สุด โมดูลอื่นๆ โมดูลไม่ควรมีความรู้เกี่ยวกับการทำงานภายในของ โมดูลอื่นๆ
  • มีความสอดคล้องกันสูงหมายความว่าโมดูลควรประกอบด้วยชุดของโค้ดที่ ทำหน้าที่เป็นระบบ ลูกค้าควรกำหนดความรับผิดชอบไว้อย่างชัดเจนและ อยู่ภายในขอบเขตของความรู้ด้านโดเมนบางอย่าง ลองใช้ตัวอย่าง eBook แอปพลิเคชัน การใช้รหัสที่เกี่ยวกับหนังสือและการชำระเงินร่วมกันอาจไม่เหมาะสม อยู่ในโมดูลเดียวกัน เนื่องจากเป็นโดเมนที่ใช้งานได้ 2 โดเมน

ประเภทโมดูล

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

โมดูลข้อมูล

โดยปกติโมดูลข้อมูลจะมีที่เก็บ แหล่งข้อมูล และคลาสของโมเดล ความรับผิดชอบหลัก 3 อย่างของโมดูลข้อมูลคือ

  1. สรุปข้อมูลและตรรกะทางธุรกิจทั้งหมดของโดเมนหนึ่งๆ: ข้อมูลแต่ละรายการ ควรรับผิดชอบในการจัดการข้อมูลที่แสดง จัดการข้อมูลได้หลายประเภทตราบใดที่ยังเกี่ยวข้องกัน
  2. แสดงที่เก็บเป็น API ภายนอก: API สาธารณะของข้อมูล โมดูลควรเป็นที่เก็บ เนื่องจากโมดูลดังกล่าวมีหน้าที่ในการเปิดเผยข้อมูลแก่ ที่เหลือในแอปด้วย
  3. ซ่อนรายละเอียดการใช้งานและแหล่งข้อมูลทั้งหมดจากภายนอก ที่เก็บจากโมดูลเดียวกันควรเข้าถึงแหล่งข้อมูลได้ โดยจะยังคงซ่อนตัวอยู่ด้านนอก คุณบังคับใช้สิ่งนี้ได้โดยใช้ Kotlin คีย์เวิร์ดระดับการมองเห็น private หรือ internal
รูปที่ 1 ตัวอย่างโมดูลข้อมูลและเนื้อหา

โมดูลฟีเจอร์

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

รูปที่ 2 แต่ละแท็บของแอปพลิเคชันนี้สามารถกำหนดเป็นฟีเจอร์ได้

ฟีเจอร์ต่างๆ เชื่อมโยงกับหน้าจอหรือปลายทางในแอป ดังนั้น ก็มักจะมี UI ที่เชื่อมโยงและ ViewModel เพื่อจัดการกับตรรกะ และสถานะ สถานที่หนึ่งไม่จำเป็นต้องจำกัดอยู่ที่การดูครั้งเดียวหรือ ปลายทางการนำทาง โมดูลฟีเจอร์ขึ้นอยู่กับโมดูลข้อมูล

รูปที่ 3 ตัวอย่างโมดูลฟีเจอร์และเนื้อหา

โมดูลแอป

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

วันที่
รูปที่ 4 กราฟทรัพยากร Dependency ของโมดูลเวอร์ชันผลิตภัณฑ์ *การสาธิต* และ *เวอร์ชันเต็ม*

หากแอปกำหนดเป้าหมายอุปกรณ์หลายประเภท เช่น อัตโนมัติ, อุปกรณ์สวมใส่ หรือ TV ให้กำหนดโมดูลแอปสำหรับแต่ละอุปกรณ์ ซึ่งจะช่วยแยกแพลตฟอร์มเฉพาะ ทรัพยากร Dependency

รูปที่ 5 กราฟทรัพยากร Dependency ของแอป Wear

โมดูลทั่วไป

โมดูลทั่วไป หรือที่เรียกว่าโมดูลหลัก มีโค้ดที่โมดูลอื่นๆ ที่ใช้บ่อย โดยช่วยลดความซ้ำซ้อนและไม่แสดงถึงชั้นใดชั้นหนึ่งโดยเฉพาะใน สถาปัตยกรรมของแอป ต่อไปนี้เป็นตัวอย่างของโมดูลทั่วไป

  • โมดูล UI: หากคุณใช้องค์ประกอบ UI ที่กำหนดเองหรืออธิบายการสร้างแบรนด์อย่างละเอียดใน คุณควรรวมคอลเล็กชันวิดเจ็ตของคุณไว้เป็นโมดูล เพื่อนำฟีเจอร์ทั้งหมดมาใช้ใหม่ ซึ่งจะช่วยให้ UI สอดคล้องกัน ฟีเจอร์ต่างๆ ได้ เช่น หากธีมอยู่ในศูนย์กลาง คุณก็หลีกเลี่ยง การเปลี่ยนโครงสร้างใหม่อันน่าเจ็บปวดเมื่อต้องรีแบรนด์
  • โมดูล Analytics: การติดตามมักจะกำหนดโดยข้อกำหนดทางธุรกิจที่มี ด้านสถาปัตยกรรมซอฟต์แวร์เล็กน้อย ได้แก่ มักจะใช้ในคอมโพเนนต์ที่ไม่เกี่ยวข้อง ถ้าหากเป็นเช่นนั้น คุณอาจ คุณควรมีโมดูลการวิเคราะห์โดยเฉพาะ
  • โมดูลเครือข่าย: เมื่อโมดูลจำนวนมากต้องใช้การเชื่อมต่อเครือข่าย คุณอาจ ให้พิจารณาการมีโมดูลเฉพาะสำหรับการจัดหาไคลเอ็นต์ HTTP ใช่เลย มีประโยชน์เป็นพิเศษเมื่อไคลเอ็นต์ของคุณต้องการกำหนดค่าที่กำหนดเอง
  • โมดูลยูทิลิตี: ยูทิลิตีหรือที่เรียกว่าผู้ช่วยมักจะเป็นหน่วยเล็กๆ ของโค้ด ที่จะมีการใช้งานซ้ำในแอปพลิเคชัน ตัวอย่างของยูทิลิตี ได้แก่ เครื่องมือช่วยทดสอบ ฟังก์ชันการจัดรูปแบบสกุลเงิน เครื่องมือตรวจสอบอีเมล

โมดูลทดสอบ

โมดูลทดสอบคือโมดูล Android ที่ใช้เพื่อการทดสอบเท่านั้น โมดูลนี้ประกอบด้วยโค้ดทดสอบ ทรัพยากรทดสอบ และทรัพยากร Dependency ทดสอบที่ จำเป็นสำหรับการเรียกใช้การทดสอบและไม่จำเป็นต้องใช้ในระหว่างรันไทม์ของแอปพลิเคชัน โมดูลการทดสอบจะถูกสร้างขึ้นเพื่อแยกโค้ดเฉพาะสำหรับการทดสอบออกจากโค้ดหลัก ทำให้จัดการและดูแลรักษาโค้ดโมดูลได้ง่ายขึ้น

กรณีการใช้งานสำหรับโมดูลทดสอบ

ตัวอย่างต่อไปนี้จะแสดงสถานการณ์ที่การใช้งานโมดูลทดสอบ อาจมีประโยชน์อย่างยิ่ง เช่น

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

  • การกำหนดค่าบิลด์ที่สะอาดตา: โมดูลทดสอบช่วยให้คุณกำหนดค่าอย่างราบรื่น การกำหนดค่าบิลด์ เนื่องจากผู้ใช้สามารถมีไฟล์ build.gradle ของตัวเองได้ ไม่ได้นะ ต้องทำให้ไฟล์ build.gradle ของโมดูลแอปกระจัดกระจายด้วยการกำหนดค่า เกี่ยวข้องกับการทดสอบเท่านั้น

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

  • แอปพลิเคชันขนาดใหญ่: โมดูลทดสอบมีประโยชน์อย่างยิ่งสำหรับ แอปพลิเคชันขนาดใหญ่ซึ่งมีโค้ดเบสที่ซับซ้อนและโมดูลจำนวนมาก ในกรณีดังกล่าว โมดูลทดสอบสามารถช่วยปรับปรุงการจัดระเบียบโค้ดและการบำรุงรักษา

รูปที่ 6 โดยจะใช้โมดูลทดสอบเพื่อแยกโมดูลที่ต้องพึ่งพากันและกันได้

การสื่อสารระหว่างโมดูล

โมดูลแทบจะไม่มีอยู่ในการแยกกันโดยสิ้นเชิงและมักจะอาศัยโมดูลอื่นๆ และ สื่อสารกับพวกเขา สิ่งสำคัญคือต้องทำให้ตัวคู่เชื่อมต่ออยู่ในระดับต่ำแม้ว่าจะเป็นโมดูล ทำงานร่วมกันและแลกเปลี่ยนข้อมูลกันเป็นประจำ โดยตรงในบางครั้ง การสื่อสารระหว่าง 2 โมดูลนั้นไม่เป็นที่ต้องการ อย่างในกรณีของ ทางสถาปัตยกรรม และอาจเป็นไปไม่ได้ เช่น ในกรณีของวงจร ทรัพยากร Dependency

รูปที่ 7 การสื่อสารโดยตรงแบบ 2 ทางระหว่างโมดูลทำไม่ได้เพราะทรัพยากร Dependency แบบวนซ้ำ โมดูลสื่อกลางเป็นสิ่งจำเป็นเพื่อประสานงานการรับส่งข้อมูลระหว่างโมดูลอิสระอีก 2 รายการ

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

navController.navigate("checkout/$bookId")

ปลายทางการชำระเงินจะได้รับรหัสหนังสือเป็นอาร์กิวเมนต์ที่ใช้ ดึงข้อมูลเกี่ยวกับหนังสือ คุณใช้แฮนเดิลสถานะที่บันทึกไว้เพื่อ ดึงอาร์กิวเมนต์การนำทางภายใน ViewModel ของฟีเจอร์ปลายทาง

class CheckoutViewModel(savedStateHandle: SavedStateHandle, ) : ViewModel() {

   val uiState: StateFlow<CheckoutUiState> =
      savedStateHandle.getStateFlow<String>("bookId", "").map { bookId ->
          // produce UI state calling bookRepository.getBook(bookId)
      }
      
}

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

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

รูปที่ 8 โมดูลฟีเจอร์ 2 รายการที่ต้องใช้โมดูลข้อมูลที่แชร์

การกลับการขึ้นต่อกัน

การกลับการขึ้นต่อกันคือเมื่อคุณจัดระเบียบโค้ดในลักษณะที่เป็นแอบสแตรกต์ แยกจากการนำไปใช้ที่เป็นรูปธรรม

  • ตัวย่อ: สัญญาที่ระบุวิธีองค์ประกอบหรือโมดูลใน ที่แอปพลิเคชันจะโต้ตอบระหว่างกัน โมดูล Abstraction จะกำหนด API ของ ระบบของคุณ และมีอินเทอร์เฟซและโมเดลต่างๆ
  • การติดตั้งใช้งานอย่างเป็นรูปธรรม: โมดูลที่ขึ้นอยู่กับโมดูลแอบสแตรกชัน และนำพฤติกรรมของนามธรรมมาใช้

โมดูลที่อาศัยลักษณะการทำงานที่ระบุไว้ในโมดูล Abstraction ควร ขึ้นอยู่กับวิธีการใช้งานแบบแอบสแตรกต์ ไม่ใช่วิธีการติดตั้งใช้งานที่เจาะจง

รูปที่ 9 ทั้งนี้ ระดับสูงและโมดูลการติดตั้งใช้งานจะขึ้นอยู่กับโมดูล Abstraction แทนโมดูลระดับสูงที่ขึ้นอยู่กับโมดูลระดับต่ำโดยตรง

ตัวอย่าง

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

เพื่อให้บรรลุเป้าหมายนี้ โมดูลฟีเจอร์จะขึ้นอยู่กับโมดูล Abtraction มากกว่า ในการใช้งานฐานข้อมูลเฉพาะ นามธรรมนี้อธิบายถึง API ของฐานข้อมูล กล่าวอีกนัยหนึ่งคือ จะเป็นการตั้งกฎสำหรับวิธีโต้ตอบกับ ฐานข้อมูล วิธีนี้ช่วยให้โมดูลฟีเจอร์ใช้ฐานข้อมูลได้โดยไม่จำเป็นต้อง ทราบรายละเอียดการใช้งานที่สำคัญ

โมดูลการติดตั้งใช้งานที่เป็นรูปธรรมแสดงการนำไปใช้จริงของ API ที่กำหนดไว้ในโมดูลแอบสแตรกต์ ในการทำเช่นนั้น การติดตั้งใช้งาน ขึ้นอยู่กับโมดูลแอบสแตรกชันด้วย

การแทรกการขึ้นต่อกัน

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

releaseImplementation(project(":database:impl:firestore"))

debugImplementation(project(":database:impl:room"))

androidTestImplementation(project(":database:impl:mock"))

ข้อดี

ข้อดีของการแยก API ออกจากการใช้งานมีดังนี้

  • ความสามารถในการแลกเปลี่ยน: มีการแยก API และการใช้งานออกจากกันอย่างชัดเจน คุณสามารถพัฒนาการใช้งานหลายอย่างสำหรับ API เดียวกัน และ ระหว่างแท็กดังกล่าวโดยไม่เปลี่ยนโค้ดที่ใช้ API อาจเป็น มีประโยชน์อย่างยิ่งในสถานการณ์ที่คุณต้องการมอบ ความสามารถหรือพฤติกรรมในบริบทต่างๆ เช่น ตัวอย่าง ในการนำไปใช้งานทดสอบเทียบกับการใช้งานจริงสำหรับเวอร์ชันที่ใช้งานจริง
  • การแยกส่วน: การแยกหมายความว่าโมดูลที่ใช้นามธรรมจะไม่ ขึ้นอยู่กับเทคโนโลยีที่เจาะจง หากคุณเลือกเปลี่ยนฐานข้อมูลจาก เพิ่มพื้นที่ให้ Firestore ในภายหลัง การทำเช่นนี้น่าจะง่ายกว่าเนื่องจากการเปลี่ยนแปลงจะมี ในโมดูลเฉพาะที่ทํางาน (โมดูลการติดตั้งใช้งาน) และจะไม่ ส่งผลต่อโมดูลอื่นๆ ที่ใช้ API ของฐานข้อมูลของคุณ
  • ความสามารถในการทดสอบ: การแยก API ออกจากการใช้งาน ช่วยอำนวยความสะดวกในการทดสอบ คุณเขียนกรอบการทดสอบเทียบกับสัญญา API ได้ คุณสามารถ และใช้งานแบบต่างๆ เพื่อทดสอบสถานการณ์และกรณีปัญหาที่อาจพบได้ต่างกัน รวมถึงการนำไปใช้งานจำลอง
  • ประสิทธิภาพของบิลด์ที่ดีขึ้น: เมื่อแยก API และ API การนำไปใช้งานในโมดูลต่างๆ การเปลี่ยนแปลงในการนำไปใช้งาน โมดูลไม่บังคับให้ระบบบิลด์คอมไพล์โมดูลซ้ำ ทั้งนี้ขึ้นอยู่กับ โมดูล API ซึ่งนำไปสู่การสร้างที่เร็วขึ้น และมีประสิทธิภาพการทำงานเพิ่มขึ้น โดยเฉพาะอย่างยิ่งในโปรเจ็กต์ขนาดใหญ่ที่ใช้เวลาสร้างค่อนข้างนาน

กรณีที่ควรแยกทาง

การแยก API ออกจากการใช้งานใน กรณีต่อไปนี้

  • ความสามารถที่หลากหลาย: หากคุณใช้งานส่วนต่างๆ ของระบบได้ใน API ที่ชัดเจนช่วยให้สามารถสลับสับเปลี่ยนกันได้ การนำไปใช้งานจริง ตัวอย่างเช่น คุณอาจมีระบบการแสดงผลที่ใช้ OpenGL หรือ Vulkan หรือระบบการเรียกเก็บเงินที่ทำงานร่วมกับ Play หรือการเรียกเก็บเงินภายในองค์กรของคุณได้ API
  • แอปพลิเคชันหลายรายการ: หากคุณพัฒนาแอปพลิเคชันหลายรายการด้วย ความสามารถที่มีร่วมกันสำหรับแพลตฟอร์มต่างๆ คุณสามารถกำหนด API ทั่วไปและ พัฒนาการใช้งานที่เฉพาะเจาะจงต่อแพลตฟอร์ม
  • ทีมอิสระ: การแยกส่วนช่วยให้นักพัฒนาแอปหรือทีมต่างๆ ทำงานในส่วนต่างๆ ของฐานของโค้ดได้พร้อมกัน นักพัฒนาซอฟต์แวร์ควรให้ความสำคัญ เกี่ยวกับการทำความเข้าใจสัญญา API และใช้งานอย่างถูกต้อง ลูกค้าไม่จำเป็นต้อง กังวลเรื่องรายละเอียดการใช้งานโมดูลอื่นๆ
  • Codebase ขนาดใหญ่: เมื่อ Codebase มีขนาดใหญ่หรือซับซ้อน ซึ่งจะแยก API ออกจากกัน จากการติดตั้งทำให้โค้ดสามารถจัดการได้ง่ายขึ้น ซึ่งจะช่วยให้คุณแบ่ง Codebase ต่างๆ ลงเป็นหน่วยแบบละเอียด เข้าใจได้ และดูแลรักษาได้

วิธีใช้

หากต้องการใช้การกลับทรัพยากร Dependency ให้ทำตามขั้นตอนต่อไปนี้

  1. สร้างโมดูล Abstraction: โมดูลนี้ควรมี API (อินเทอร์เฟซ) และโมเดล) ที่กำหนดลักษณะการทำงานของฟีเจอร์
  2. สร้างโมดูลการใช้งาน: โมดูลการใช้งานควรยึดตาม โมดูล API และใช้ลักษณะการทำงานของแอบสแตรกต์
    ทั้งนี้ ระดับสูงและโมดูลการติดตั้งใช้งานจะขึ้นอยู่กับโมดูล Abstraction แทนโมดูลระดับสูงที่ขึ้นอยู่กับโมดูลระดับต่ำโดยตรง
    รูปที่ 10 โมดูลการติดตั้งใช้งานจะขึ้นอยู่กับโมดูลแอบสแตรกชัน
  3. ทำให้โมดูลระดับสูงต้องใช้โมดูล Abstraction: แทนที่จะใช้ โดยตรงโดยขึ้นอยู่กับการติดตั้งใช้งานเฉพาะ ให้โมดูลของคุณขึ้นอยู่กับ โมดูลแอบสแตรกต์ โมดูลระดับสูงไม่จำเป็นต้องทราบการติดตั้งใช้งาน พวกเขาต้องใช้สัญญา (API) เท่านั้น
    โมดูลระดับสูงจะขึ้นอยู่กับนามธรรม ไม่ใช่การนำไปใช้
    รูปที่ 11 โมดูลระดับสูงจะขึ้นอยู่กับนามธรรม ไม่ใช่การนำไปใช้
  4. ระบุโมดูลการติดตั้งใช้งาน: สุดท้าย คุณต้องให้ การใช้งานสำหรับทรัพยากร Dependency ของคุณ การติดตั้งใช้งานเฉพาะจะขึ้นอยู่กับ การตั้งค่าโปรเจ็กต์ได้ แต่โมดูลแอปมักจะเป็นตำแหน่งที่เหมาะสม หากต้องการติดตั้งใช้งาน ให้ระบุเป็นการพึ่งพาที่คุณเลือก ตัวแปรของบิลด์หรือชุดแหล่งที่มาของการทดสอบ
    โมดูลแอปแสดงการใช้งานจริง
    รูปที่ 12 โมดูลแอปจะนำเสนอการใช้งานจริง

แนวทางปฏิบัติแนะนำโดยทั่วไป

อย่างที่กล่าวไปแล้วข้างต้น ไม่มีวิธีที่ถูกต้องเพียงวิธีเดียวในการพัฒนา แอปหลายโมดูล เช่นเดียวกับที่มี สถาปัตยกรรมซอฟต์แวร์จำนวนมาก ทำให้แอปแยกเป็นโมดูลได้หลากหลายวิธี อย่างไรก็ตาม หลักเกณฑ์ต่อไปนี้ จะช่วยให้คุณทำให้โค้ดอ่าน บำรุงรักษา และทำให้โค้ดของคุณอ่านง่ายขึ้น สามารถทดสอบได้

กำหนดค่าให้สอดคล้องกัน

ทุกโมดูลจะมีโอเวอร์เฮดการกำหนดค่า หากจำนวนโมดูลของคุณ ถึงเกณฑ์ที่กำหนด การจัดการการกำหนดค่าที่สอดคล้องกันจะกลายเป็น ชาเลนจ์ ตัวอย่างเช่น โมดูลควรใช้ทรัพยากร Dependency ของโมดูลเดียวกัน เวอร์ชัน หากคุณต้องการอัปเดตโมดูลจำนวนมาก เพื่อยกระดับ เวอร์ชัน Dependency นั้น ไม่ใช่แค่การลงแรง แต่ยังเป็นโอกาส ข้อผิดพลาด คุณแก้ปัญหาได้ด้วยเครื่องมือของ Gradle เพื่อ รวมศูนย์การกำหนดค่า:

  • แคตตาล็อกเวอร์ชันเป็นรายการทรัพยากร Dependency ที่ปลอดภัยประเภทหนึ่ง ที่ Gradle สร้างขึ้นระหว่างการซิงค์ ซึ่งเป็นศูนย์กลางสำหรับการประกาศ ทรัพยากร Dependency และพร้อมใช้งานสำหรับโมดูลทั้งหมดในโปรเจ็กต์
  • ใช้ปลั๊กอินระเบียบเพื่อแชร์ตรรกะบิลด์ระหว่างโมดูล

แสดงให้เห็นน้อยที่สุด

อินเทอร์เฟซสาธารณะของโมดูลควรมีขนาดเล็กและเปิดเผยเฉพาะ ข้อมูลสำคัญ ไม่ควรทำให้รายละเอียดการใช้งานภายนอกรั่วไหล ขอบเขต ให้เหลือน้อยที่สุดเท่าที่จะเป็นไปได้ ใช้ private หรือ internal ของ Kotlin ระดับการมองเห็นเพื่อทำให้โมดูลการประกาศเป็นแบบส่วนตัว เมื่อประกาศ ทรัพยากร Dependency ในโมดูลของคุณ ให้ใช้ implementation มากกว่า api รายการหลัง จะแสดงทรัพยากร Dependency แบบทรานซิทีฟให้แก่ผู้บริโภคของโมดูล การใช้ อาจช่วยปรับปรุงเวลาบิลด์ เนื่องจากจะลดจํานวนโมดูล ที่ต้องสร้างใหม่

ต้องการใช้ Kotlin และ โมดูล Java

Android Studio รองรับโมดูลที่จำเป็น 3 ประเภทดังนี้

  • โมดูลแอปเป็นจุดแรกเข้าของแอปพลิเคชัน ซึ่งอาจมี ซอร์สโค้ด ทรัพยากร เนื้อหา และ AndroidManifest.xml เอาต์พุตของ โมดูลแอปคือ Android App Bundle (AAB) หรือแพ็กเกจแอปพลิเคชัน Android (APK)
  • โมดูลไลบรารีมีเนื้อหาเดียวกันกับโมดูลแอป นั่นคือ ที่โมดูล Android อื่นๆ ใช้เป็นทรัพยากร Dependency เอาต์พุตของโมดูลไลบรารี เป็น Android Archive (AAR) ซึ่งมีโครงสร้างเหมือนกันกับโมดูลแอปแต่ ถูกคอมไพล์ไปยังไฟล์ Android Archive (AAR) ซึ่งผู้ใช้คนอื่นสามารถนำมาใช้ในภายหลังได้ โมดูลโดเมนขึ้นต่อกัน โมดูลห้องสมุดช่วยให้ ห่อหุ้มและนำตรรกะและทรัพยากรเดียวกันมาใช้ซ้ำในโมดูลแอปจำนวนมาก
  • ไลบรารี Kotlin และ Java ไม่มีทรัพยากร เนื้อหา หรือ Manifest

เนื่องจากโมดูล Android มาพร้อมกับค่าใช้จ่าย หากเป็นไปได้ คุณควรใช้ Kotlin หรือ Java ให้มากที่สุดเท่าที่จะเป็นไปได้