DAO ควรเป็นแบบเดี่ยวหรือไม่?


14

ฉันกำลังพัฒนา RESTful API และฉันคิดว่ามันสะดวกที่จะใช้ DAO สำหรับทรัพยากรของฉันเพราะแม้ว่าฉันจะใช้หน่วยความจำเพื่อเก็บไว้ แต่ฉันไม่ต้องการปิดประตูให้ใครก็ตามที่ใช้ห้องสมุดของฉันถ้าพวกเขาตัดสินใจที่จะใช้ การใช้ฐานข้อมูลสำหรับ DAO

คำถามของฉันคือว่า DAO ควรเป็นซิงเกิลตันหรือไม่ หากไม่ใช่บริการจะมีตัวอย่างของ DAO และจะมีลักษณะเช่นนี้:

@Path("eventscheduler")
public class EventSchedulerService {
    private IEventSchedulerDao dao = new EventSchedulerDao();

    // in case a different implementation is to be used
    public void setEventSchedulerDao(IEventSchedulerDao dao) {
        this.dao = dao;
    }

    @Path("{uniqueName}")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Tournament getTournament(@PathParam("name") String uniqueName) {
        return dao.get(uniqueName);
    }

    @Path("create")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Tournament createTournament(Tournament tournament) {
        return dao.create(tournament);
    }
}

ในขณะที่ถ้า DAO เป็นซิงเกิลตัน แต่ฉันคิดว่าคงไม่แตกต่างกันมากนักในบรรทัดแรก:

private IEventSchedulerDao dao = EventSchedulerDao.getInstance();

ฉันจะยังคงต้องใช้IEventSchedulerDaoอินสแตนซ์ แต่ฉันเดาว่าซิงเกิลตันทั้งหมดทำงานเช่นนี้ใช่ไหม ด้วยเหตุผลบางอย่างฉันมักจะมีความสัมพันธ์กับซิงเกิลตันกับวิธีการแบบสแตติกเสมอดังนั้นแทนที่จะมีผู้ใช้ที่มีอินสแตนซ์เดี่ยวปรากฏให้เห็นสิ่งgetInstance()นี้จะถูกซ่อนและเขา / เธอจะใช้EventSchedulerDao.get(name)ฯลฯ ในลักษณะคงที่ นี่เป็นสิ่งหรือเป็นเพียงฉันหรือไม่

ดังนั้นฉันควรหรือไม่ควรมี DAO แบบซิงเกิล?

และเป็นคำถามข้างเคียงมันเป็นวิธีการของฉันที่จะมีประตูเปิดสำหรับผู้ใช้ในการใช้ DAO ของตัวเอง?


คุณสามารถใช้ IoC singleton แทน singleton กับ static accessor
CodesInChaos

คำตอบ:


10

ฉันจะไม่ใช้ซิงเกิล มันเป็นรูปแบบการต่อต้านที่เป็นที่รู้จักและทำให้การทดสอบเป็นเรื่องยาก ฉันอยากจะฉีดในการนำไปปฏิบัติอย่างเป็นรูปธรรมและให้บริการของคุณอ้างอิงอินเทอร์เฟซ DAO (ให้คุณฉีดการนำไปใช้ที่ต่างกัน)


1
สิ่งที่คุณแนะนำในประโยคสุดท้ายของคุณคือสิ่งที่ฉันทำถูกต้อง?
dabadaba

1
คุณกำลังอ้างอิงผ่านอินเทอร์เฟซ (ใช่) แต่คุณไม่ได้ฉีด DAO (เพื่อให้ชัดเจน .... )
Brian Agnew

คุณหมายถึงอะไร ฉันมีหมาตัวหนึ่งใช่ไหม
dabadaba

@dabadaba บรรทัดprivate IEventSchedulerDao dao = new EventSchedulerDao();ที่คุณทำผิดไป การใช้งานสำหรับIEventSchedulerDaoควรถูกฉีดผ่านทางนวกรรมิกและไม่เคยเปลี่ยนแปลง (เช่นกำจัดsetEventSchedulerDaoด้วย)
David Arno

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

4

D ATA ccess O bject ควรเท่านั้นจริงๆมีอยู่ครั้งหนึ่งในแอพลิเคชันของคุณ ตรรกะยังคงเหมือนเดิมสิ่งเดียวที่แตกต่างกันคือค่าที่เข้าและออกจากวิธีการที่ DAO ให้

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

ขออภัยถ้าไวยากรณ์ไม่ถูกต้องฉันไม่ใช่โปรแกรมเมอร์ Java

class DaoSingletonFactory
{
    private static Dao dao = null;

    public static Dao getInstance()
    {
        if (DaoSingletonFactory.dao == null) {
            DaoSingletonFactory.dao = new Dao();
        }

        return DaoSingletonFactory.dao;
    }
}

class UsesDao
{
    public void someMethod()
    {
        Dao dao = DaoSingletonFactory.getInstance();
    }
}

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

จากนั้นก็มีวิธีที่ดีกว่าเดี่ยวอ่อนแอรูปแบบที่คุณไม่เรียกเช่นผ่านstaticวิธี แต่ให้เรียนทั้งหมดขึ้นอยู่กับอินสแตนซ์ทั้งผ่านคอนสตรัคหรือหมา (ในของคุณEventSchedulerServiceคุณกำลังใช้การฉีดหมา)

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

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

โชคดีที่มีคอนเทนเนอร์IoCซึ่งทำให้ง่ายขึ้นมาก นอกจากSpringแล้วGuice IoC container ของ Google ก็เป็นที่นิยมในหมู่โปรแกรมเมอร์ Java

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

คุณสามารถตรวจสอบลิงค์นี้เพื่อดูตัวอย่างเดี่ยวด้วย Guice


ข้อดีและข้อเสียของการใช้คอนเทนเนอร์ IoC

ข้อดี

  • ประหยัดงบประมาณโดยไม่ต้องเขียนวิธีการจากโรงงานทั้งหมดด้วยตัวเอง
  • (ปกติ) การกำหนดค่าที่ตรงไปตรงมามาก
  • การพัฒนาอย่างรวดเร็ว

จุดด้อย

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

1

Singletonอ้างถึงแนวคิดเพียงหนึ่งอินสแตนซ์และวิธีเข้าถึงอินสแตนซ์ (ผ่านเมธอดสแตติกที่มีชื่อเสียงดังนั้นgetInstance ( )

แต่ก็ยังมีตัวอย่างอยู่เบื้องหลังทั้งหมด วัตถุที่สร้างขึ้นพร้อมการ จำกัด การเข้าถึง

ในกรณีของคุณฉันอยากจะไปหา DI (การฉีดพึ่งพา) เช่นเดียวกับบล็อคแรกของรหัสที่คุณได้สัมผัส เพียงแค่การเปลี่ยนแปลงเล็กน้อย ฉีด DAO ผ่านคอนสตรัคเตอร์ ในการลบหรือไม่ตัวติดตั้งนั้นขึ้นอยู่กับคุณ หากคุณต้องการปกป้องตัวควบคุมจากการเปลี่ยนแปลงในรันไทม์ให้ลบออก หากคุณต้องการเสนอความเป็นไปได้ให้เก็บไว้

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

เพียงคำใบ้ ทรัพยากรแบบคงที่ (วัตถุวิธีการค่าคงที่หรือตัวแปร) เป็นเหมือนทรัพยากรทั่วโลก ถ้ากลมเป็นสิ่งชั่วร้ายหรือไม่เป็นเรื่องของความต้องการหรือรสนิยม อย่างไรก็ตามมีข้อบกพร่องโดยนัยที่ผูกพันกับพวกเขา สิ่งเหล่านี้เกี่ยวข้องกับการทำงานพร้อมกัน , ความปลอดภัยของเธรด (ใน Java, ไม่ทราบเกี่ยวกับภาษาอื่น ๆ ), การทำให้เป็นอนุกรม ...

ดังนั้นฉันขอแนะนำให้ใช้สถิตยศาสตร์อย่างระมัดระวัง

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