ฉันจะโครงสร้างอินเทอร์เฟซเมื่อวัตถุใช้เพียงส่วนหนึ่งของอินเทอร์เฟซได้อย่างไร


9

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

ถ้าฉันใช้คลาสเหมือนเดิมมันใช้งานได้ดี แต่ฉันมีปัญหากับความจริงที่ว่าแต่ละคลาสต้องการฟังก์ชันการทำงานที่ไม่ได้ใช้งาน ตัวอย่างเช่นในการใช้คลาส A ฉันต้องส่งผ่าน dao ที่ใช้ฟังก์ชั่นลบแม้ว่ามันจะไม่ถูกเรียกใช้ ในทำนองเดียวกันฉันต้องผ่านคลาส B a dao ที่ใช้ฟังก์ชั่นการอ่าน แต่มันจะไม่ถูกเรียก

ฉันคิดเกี่ยวกับการเข้าถึงโดยการมีส่วนต่อประสานที่สืบทอดผู้อื่น (IReadDao, IUpdateDao, IDeleteDao เป็น daos ที่จะสืบทอดมาจาก) แต่วิธีการนี้โดยทั่วไปจะต้องใช้อินเทอร์เฟซที่แตกต่างกันสำหรับฟังก์ชั่นแต่ละชุด (IUpdateAndDelete )

ฉันต้องการใช้อินเทอร์เฟซสำหรับ dao เพราะฉันไม่ต้องการเชื่อมโยงแอปพลิเคชันกับฐานข้อมูล มีรูปแบบหรือวิธีการในการบรรลุสิ่งที่ฉันต้องการให้ใครรู้หรือไม่? ขอบคุณล่วงหน้า.

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
เหตุใดคุณจึงต้องการอินเทอร์เฟซแยกสำหรับแต่ละชุดเมื่อเทียบกับการมีแต่ละคลาสที่ใช้พวกเขาใช้สิ่งที่พวกเขาต้องการ?
yitzih

ในกรณีข้างต้นแทนที่จะส่ง IDao ไปยังตัวสร้างของ A ฉันจะต้องผ่านวัตถุที่ใช้ IUpdate และ IRead ดังนั้นประเภทของตัวแปรอินสแตนซ์ "dao" จะเป็นอย่างไร มันจะต้องเป็นอะไรที่เหมือน IUpdateAndReadDao หรือไม่? ยังคงต้องเป็นส่วนต่อประสานเพราะถ้าฉันบอกให้ใช้งานซึ่งเป็นฐานข้อมูลเฉพาะฉันได้เชื่อมคลาสกับฐานข้อมูล นั่นคือสิ่งที่คุณถาม
jteezy14

3
ฉันคิดว่านี่เป็นตัวอย่างที่สมบูรณ์แบบของหลักการแยกส่วนต่อประสาน ( IจากSOLID) อาจต้องการอ่านสักหน่อย
Christopher Francisco

คำตอบ:


10

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

เพื่อหลีกเลี่ยงการระเบิด combinatorial (เช่นเพื่อหลีกเลี่ยงความจำเป็นในการที่IReadUpdate, IDeleteUpdateฯลฯ อินเตอร์เฟซ) คุณสามารถให้การเชื่อมต่อแยกต่างหากในการฉีดคอนสตรัค (คุณสามารถผ่านวัตถุเดียวกันสองครั้งเป็นพารามิเตอร์ที่แตกต่างกัน) หรือให้การสนับสนุนวัตถุเดียวสองคนหรือมากกว่าการเชื่อมต่อ extendsในวิธีการเรียกใช้ทั่วไป

การสร้างคอนสตรัค:

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

Setter injection โดยใช้วิธีทั่วไป:

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

เมื่อใช้ setter injection ฉันจะประกาศตัวแปรอินสแตนซ์ที่ฉันตั้งไว้ในฟังก์ชัน InitializeDao ได้อย่างไร
jteezy14

คุณต้องการตัวแปรอินสแตนซ์สองตัว (หนึ่งตัวสำหรับลบ, หนึ่งตัวสำหรับการอัพเดต) ... กำหนดdaoให้ทั้งคู่
John Wu

โอ้ใช่นั่นเหมาะสมแล้ว ขอบคุณมากสำหรับคำตอบที่ยอดเยี่ยม!
jteezy14
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.