Groovy/Grails cara menjadikan konstruktor pribadi - cara yang benar

Saya memiliki kelas domain di grails yang hanya boleh dibuat sekali dengan nama yang sama. Untuk memastikan bahwa saya memiliki metode statis getColor dan konstruktor pribadi yang terlihat sebagai berikut:

class Color {
  String name

  static hasMany = [moods: Mood] 

  // not accessible
  private Color() {}

  // not accessible because getColor should be used
  private Color(String name) {
    this.name = name
  }

  static getColor(String name) {
    def color = Color.findByName(name.toLowerCase())
    color ? color : new Color(name).save(flush:true) 
  }

  def beforeValidate() {
    name = name.toLowerCase();
  }
}

untuk memastikan bahwa objek Warna hanya dibuat dengan menggunakan metode getColor statis, saya ingin menjadikan konstruktornya pribadi. Sejauh ini berhasil, saya bisa membuat objek Berwarna. Tetapi ketika saya menggunakan instance ini untuk membuat objek Object Mood

class Mood {

  static belongsTo = [color:Color]

}

def color = Color.getColor('verylightgreen')
def mood = new Mood(color: color)

Saya mendapat pengecualian:

error initializing the application: Could not instantiate bean class [de.tobi.app.Color]: Is the constructor accessible?

Pengecualian ini diberikan oleh

def mood = new Mood(color: color)

Jadi mengapa pembuatan Mood memerlukan akses ke konstruktor Warna. Saya sudah melewati objeknya.. Dan secara umum, apa cara terbaik di groovy/grails untuk menyembunyikan konstruktor kelas domain untuk mengontrol bagaimana objek dibuat. Terutama penggunaan pengontrol peta juga harus dinonaktifkan.


person tObi    schedule 16.08.2013    source sumber
comment
kenapa kamu tidak menggunakan Enums untuk hal semacam ini?   -  person Nathan Hughes    schedule 16.08.2013
comment
karena pengguna harus dapat menambahkan objek baru secara dinamis   -  person tObi    schedule 16.08.2013
comment
Saya pikir Anda harus mempertimbangkan penerapan keunikan melalui batasan basis data.   -  person Nathan Hughes    schedule 16.08.2013
comment
ya, pikirkan juga dan saya pikir itu akan menjadi alternatif.. tapi tetap saja menurut saya karena ini adalah pola pemrograman yang tersebar luas, saya ingin memiliki kendali tentang pembuatan objek dalam beberapa kasus, hal itu juga bisa dilakukan dengan asyik   -  person tObi    schedule 16.08.2013
comment
Apa yang menghambat Anda menjadikan name kunci utama? Dan Bagaimana Color dikaitkan dengan Mood?   -  person dmahapatro    schedule 16.08.2013
comment
ya seperti yang saya katakan, membuat nama menjadi unik dengan batasan akan menjadi alternatif dalam kasus ini. Namun pertanyaan ini dimaksudkan secara lebih umum, bagaimana saya dapat mengontrol pembuatan objek? Dan Anda benar, lupakan hubungan Warna-Suasana Hati. itu memiliki banyak. Saya akan mengeditnya di posting saya   -  person tObi    schedule 16.08.2013
comment
Kalau tidak salah Grails akan menggantikan konstruktor default untuk kelas domain, jadi menurut saya bukan ide yang baik untuk membuat konstruktor pribadi. Anda dapat menerapkan keunikan dengan batasan database.   -  person    schedule 16.08.2013


Jawaban (2)


Mengenai pengecualian:

Pengecualian terjadi karena konstruktor peta. Dengan kelas asyik yang normal, hal ini tidak menjadi masalah, tetapi grails mendaftarkan kelas domain sebagai kacang prototipe. Kemudian menimpa konstruktor di metaclass untuk menggunakan pembuatan kacang dan mekanisme pengkabelan otomatis untuk mendapatkan sebuah instance. Sesuatu di konstruktor peta dan pengkabelan otomatis menyebabkan kacang warna kosong dibuat sebelum disetel oleh peta.

Jika Anda mengubah kode menjadi:

Color c = Color.getColor('red')
Mood m = new Mood()
m.color = c
m.save()

Pengecualian akan hilang.

Anda dapat mempertimbangkan untuk mengajukan masalah JIRA untuk kasus penggunaan khusus ini, namun saya tidak tahu apakah atau bukan tim grails yang akan menganggap ini sebagai bug atau keputusan desain. Hal ini tentu saja tidak didokumentasikan di mana pun.

Mengenai desain:

Tanpa mengetahui lebih banyak tentang model Anda, saya setuju dengan dmahapatro tentang pengalihan tanggung jawab integritas data ke database Anda dan batasan GORM. Itulah gunanya mereka.

Mengabaikan hal ini menyebabkan pola penggunaan yang tidak biasa dalam kode seperti mengetahui penggunaan Color.getColor sebagai lawan dari instantiasi kelas domain normal.

Ideologi di balik konvensi mengenai kerangka konfigurasi seperti Grails adalah untuk sebisa mungkin mematuhi konvensi tersebut, sehingga siapa pun yang akrab dengan konvensi tersebut dapat ikut campur dan segera mengetahui apa yang sedang terjadi.

person codelark    schedule 16.08.2013

Menggunakan name sebagai kunci utama untuk Color Anda dapat mencapai keunikan. Selain itu, findOrSaveBy* dapat digunakan untuk menggantikan metode statis khusus getColor.

Jika menjadikan name sebagai kunci utama bukanlah pilihan yang tepat, maka Anda dapat melanjutkan dengan menambahkan batasan seperti yang disebutkan oleh hampir semua individu dalam komentar atas pertanyaan tersebut. :)

class Color {
  String name

  static mapping = {
      //column is optional
      id name: 'name', generator: 'assigned', type: 'string', column: 'NAME' 
  }

  static hasMany = [moods : Mood] //for example

  //DO NOT NEED THIS
  //This can be achieved by findOrSaveBy*
  /*static getColor(String name) {
    def color = Color.findByName(name.toLowerCase())
    color ? color : new Color(name).save(flush:true) 
  }*/

  def beforeValidate() {
    name = name.toLowerCase();
  }
}

Maka Anda bisa melakukannya dengan baik

def color = Color.findOrSaveByName('verylightgreen')
def mood = new Mood()

color.addToMoods(mood)
color.save()
person dmahapatro    schedule 16.08.2013
comment
jadi ini cara yang baik untuk membuatnya dalam kasus ini.. tetapi apakah itu berarti Anda tidak menjadikan konstruktor kelas domain Anda pribadi? - person tObi; 16.08.2013
comment
@tobi Tidak pernah menggunakan atau memikirkannya karena saya mendapatkan fleksibilitas itu menggunakan blok pemetaan dan batasan. - person dmahapatro; 16.08.2013
comment
@SérgioMichels Sobat, GORM sudah lama menjadi kaca Ray Ban, tergantung developer yang memakainya. ;) .Pikirkan Ratpack, rencananya adalah memiliki sesuatu seperti GORM di dalamnya. Saya akan menjadi pengembang yang paling bahagia jika melihat sesuatu seperti GORM di Node.js atau menemukan sesuatu seperti itu saat saya menggunakannya. :) - person dmahapatro; 16.08.2013
comment
@tobi Apakah jawabannya bermanfaat? Terimalah jawaban mana pun yang menurut Anda pantas untuk diterima. - person dmahapatro; 22.08.2013
comment
apakah ada perbedaan praktis dalam hal ini dalam menulis pemetaan statis = {id name 'name'} dan hanya membuat nama unik? ditulis seperti itu: batasan statis = { nama kosong:salah, unik:benar} - person tObi; 05.09.2013
comment
@tobi Ya. Karena nama dalam kasus sebelumnya adalah kunci utama, keunikan dipaksakan secara default. Dalam kasus berikutnya, setiap kali Anda melakukan operasi CRUD, constraints untuk kelas domain akan memulai validasi. Kedua kasus tersebut baik, tetapi Anda mendapatkan lebih banyak fleksibilitas dalam kasus berikutnya jika Anda tidak ingin menggunakan kunci utama yang ditetapkan tetapi meminta hibernasi untuk menangani id dan menjadikan name sebagai bidang lain. :-) - person dmahapatro; 05.09.2013
comment
terima kasih atas jawabannya. jadi saya kira menjadikan bidang nama sebagai id akan mempercepat operasi CRUD jika saya memiliki banyak objek Berwarna. Alternatifnya adalah menggunakan indexColumn. Apakah Anda lebih memilih sesuatu? - person tObi; 05.09.2013