Haruskah DAO menjadi singleton atau tidak?

14

Saya mengembangkan API tenang dan saya pikir itu nyaman untuk menggunakan DAO untuk sumber daya saya karena walaupun saya berencana hanya menggunakan memori untuk menyimpannya, saya tidak ingin menutup pintu kepada siapa pun yang menggunakan perpustakaan saya jika mereka memutuskan untuk menggunakan implementasi basis data untuk DAO.

Pertanyaan saya adalah apakah DAO harus tunggal atau tidak. Jika tidak, layanan akan memiliki instance DAO dan akan terlihat seperti ini:

@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);
    }
}

Sementara jika DAO adalah singleton, tapi saya kira tidak akan ada banyak perbedaan, hanya di baris pertama:

private IEventSchedulerDao dao = EventSchedulerDao.getInstance();

Saya masih harus menggunakan IEventSchedulerDaocontoh, tapi saya kira semua lajang bekerja seperti ini kan? Untuk beberapa alasan saya selalu menghubungkan singleton dengan metode statis, jadi alih-alih memiliki instance tunggal yang terlihat oleh pengguna getInstance(), ini akan disembunyikan dan dia hanya akan menggunakan EventSchedulerDao.get(name), dll ... dengan cara statis. Apakah ini sesuatu atau ini hanya saya?

Jadi, haruskah saya atau saya tidak memiliki DAO tunggal?

Dan sebagai pertanyaan sampingan, apakah tidak apa-apa pendekatan saya untuk membuka pintu bagi pengguna untuk mengimplementasikan DAO mereka sendiri?

dabadaba
sumber
Anda bisa menggunakan singleton IoC daripada singleton dengan accessor statis.
CodesInChaos

Jawaban:

10

Saya tidak akan menggunakan singleton. Ini adalah anti-pola yang dikenal , dan membuat pengujian menjadi sulit. Saya lebih suka menyuntikkan dalam implementasi konkret, dan meminta layanan Anda antarmuka DAO (memungkinkan Anda untuk menyuntikkan implementasi yang berbeda di)

Brian Agnew
sumber
1
Apa yang Anda sarankan dalam kalimat terakhir Anda adalah apa yang saya lakukan dengan benar?
dabadaba
1
Anda mereferensikan melalui antarmuka (ya), tetapi Anda tidak menyuntikkan DAO (untuk menjadi jelas ....)
Brian Agnew
Apa maksudmu? Saya punya setter untuk itu, bukan?
dabadaba
@dabadaba Jalurnya private IEventSchedulerDao dao = new EventSchedulerDao();adalah tempat Anda salah. Implementasi untuk IEventSchedulerDaoharus disuntikkan melalui konstruktor dan tidak pernah berubah (yaitu, singkirkan setEventSchedulerDaojuga).
David Arno
Baiklah saya mengerti. Saya hanya melakukan itu untuk memberikan DAO default dan mengubahnya akan menjadi "opsional". Tetapi mengambil saran Anda berarti memiliki konstruktor untuk layanan yang berbeda dari standar, dan sayangnya saya tidak tahu bagaimana cara kerjanya dengan Jersey karena menggunakan konstruktor default. Bagaimana pun Anda tahu cara melakukannya?
dabadaba
4

A D ata A ccess O bject seharusnya hanya benar-benar ada satu kali dalam aplikasi Anda. Logikanya tetap sama, satu-satunya hal yang berbeda adalah nilai-nilai yang masuk dan keluar dari metode yang disediakan oleh DAO.

Dengan mengingat hal itu, jelas hal pertama yang biasanya terjadi adalah menerapkan DAO sebagai singleton yang kuat , yaitu ketika Anda memiliki staticmetode pada kelas pabrik, sesuatu seperti getInstance, malas memuat instance DAO jika itu nol dan mengembalikannya.

Maaf jika sintaksnya tidak sepenuhnya benar, saya bukan programmer 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();
    }
}

Ini sangat sulit untuk diuji, karena Anda tidak dapat menukar implementasi tanpa mengubah kode UsesDaokelas. Itu bisa dilakukan melalui beberapa patch monyet , tetapi umumnya tidak dianggap sebagai praktik yang baik.

Lalu ada cara yang lebih baik, pola singleton yang lemah , di mana Anda tidak mengambil instance melalui staticmetode, tetapi membuat semua kelas bergantung pada instance baik melalui konstruktor atau setter (di Anda EventSchedulerServiceAnda menggunakan injeksi setter).

Satu-satunya masalah adalah, Anda kemudian perlu memastikan bahwa semua kelas, yang bergantung pada turunan kelas yang seharusnya hanya ada setelah siklus hidup aplikasi Anda, mengambil contoh yang sama dengan parameternya, yaitu. yang newdisebut hanya sekali pada objek DAO di seluruh aplikasi.

Jelas, ini sangat sulit untuk dilacak dan membangun objek-grafik adalah pekerjaan yang membosankan dan menjengkelkan.

Untungnya, ada wadah IOC , yang membuatnya jauh lebih mudah. Selain Spring , wadah Guice IoC oleh Google cukup populer di kalangan programmer Java.

Saat menggunakan wadah IoC, Anda mengkonfigurasinya untuk berperilaku dengan cara tertentu, yaitu. Anda memberi tahu jika bagaimana seharusnya membangun kelas-kelas tertentu dan jika beberapa kelas diperlukan sebagai dependensi, bagaimana dependensi seharusnya terlihat (apakah itu harus selalu menjadi contoh baru atau singleton) dan wadah itu menghubungkan semuanya.

Anda dapat memeriksa tautan ini untuk contoh tunggal dengan Guice.


Pro dan kontra menggunakan wadah IoC

Pro

  • hemat anggaran dengan tidak harus menulis sendiri semua metode pabrik
  • (biasanya) konfigurasi yang sangat mudah
  • perkembangan cepat

Cons

  • sihir penyihir, kelas-kelasnya entah bagaimana dibangun dan Anda tidak dapat benar-benar melihat bagaimana itu terjadi
  • sedikit penurunan kinerja karena pencarian kelas (pabrik yang ditulis secara manual akan sedikit lebih cepat)
Andy
sumber
1

Singleton merujuk pada konsep hanya satu instance dan cara untuk mendapatkan akses ke instance (melalui metode statis yang sangat terkenal, getInstance () )

Tapi masih ada contoh di balik semua itu. Objek yang dibangun dengan semacam akses terbatas.

Dalam kasus Anda, saya lebih suka menggunakan pendekatan DI (injeksi ketergantungan). Seperti blok kode pertama yang telah Anda tampilkan. Hanya sedikit perubahan. Suntikkan DAO melalui konstruktor. Untuk menghapus atau tidak setter terserah Anda. Jika Anda ingin melindungi Pengendali dari perubahan dalam runtime kemudian hapus. Jika Anda ingin menawarkan kemungkinan seperti itu, maka pertahankanlah.

Anda benar menggunakan Antarmuka dan menawarkan jendela terbuka untuk implementasi DAO lebih lanjut. Mungkin atau mungkin tidak dibutuhkan. Hanya butuh satu menit lebih banyak pekerjaan, tetapi ternyata desain Anda fleksibel. Anda DAO memori di adalah sangat umum. Sangat berguna sebagai tiruan pada saat pengujian. Atau sebagai implementasi DAO default.

Hanya sebuah petunjuk. Sumber daya statis (objek, metode, konstanta atau variabel) seperti sumber daya global. Jika global jahat atau tidak, itu masalah kebutuhan atau selera. Namun ada kelemahan implisit yang terikat pada mereka. Ini terkait dengan concurrency , thread-safety (di Jawa, tidak tahu tentang bahasa lain), serialisasi ...

Jadi saya menyarankan untuk menggunakan statika dengan hati-hati

Laiv
sumber