Groovy/Grails如何使构造函数私有-正确的方法

Groovy/Grails如何使构造函数私有-正确的方法,grails,groovy,gorm,Grails,Groovy,Gorm,我在grails中有一个域类,它应该只使用相同的名称创建一次。为了确保我有一个静态方法getColor和私有构造函数,如下所示: class Color { String name static hasMany = [moods: Mood] // not accessible private Color() {} // not accessible because getColor should be used private Color(String name

我在grails中有一个域类,它应该只使用相同的名称创建一次。为了确保我有一个静态方法getColor和私有构造函数,如下所示:

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();
  }
}
为了确保仅通过使用静态getColor方法创建Color对象,我想将构造函数设置为私有。到目前为止,我可以创建彩色对象。但是当我使用这个实例来创建对象情绪的对象时

class Mood {

  static belongsTo = [color:Color]

}

def color = Color.getColor('verylightgreen')
def mood = new Mood(color: color)
我得到一个例外:

error initializing the application: Could not instantiate bean class [de.tobi.app.Color]: Is the constructor accessible?
此异常由引发

def mood = new Mood(color: color)
那么,为什么情绪的创造需要借助色彩的构造器呢。我已经通过了这个物体。。
一般来说,groovy/grails中隐藏域类的构造函数以控制对象创建方式的最佳方法是什么。尤其是地图控制器的使用也应该禁用。

使用
名称
作为
颜色
的主键可以实现唯一性。另外,还可以用于替换自定义静态方法
getColor

如果将
name
设为主键不是一个可行的选择,那么您可以继续添加一个约束条件,几乎所有人都在对问题的评论中提到了这一点。:)

那你就可以做得很好了

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

color.addToMoods(mood)
color.save()

使用
name
作为
Color
的主键可以实现唯一性。另外,还可以用于替换自定义静态方法
getColor

如果将
name
设为主键不是一个可行的选择,那么您可以继续添加一个约束条件,几乎所有人都在对问题的评论中提到了这一点。:)

那你就可以做得很好了

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

color.addToMoods(mood)
color.save()

关于例外情况:

由于映射构造函数,正在发生异常。对于普通groovy类,这不是问题,但grails将域类注册为原型bean。然后它重写元类中的构造函数,以使用bean创建和自动连接机制来获取实例。映射构造函数和自动连接中的某些内容导致在映射设置之前创建一个空的色豆

如果将代码更改为:

Color c = Color.getColor('red')
Mood m = new Mood()
m.color = c
m.save()
例外情况应该消失

你可以考虑为这个特定的用例提交一个文件,但是我不知道GRAILS团队是否会认为这是一个bug或一个设计决定。它肯定没有任何地方被记录在案

关于设计:

在不太了解您的模型的情况下,我同意dmahapatro将数据完整性的责任转移到数据库和GORM约束上。这就是他们的目的

避免这种情况会导致代码中出现异常的使用模式,例如知道如何使用
Color.getColor
,而不是正常的域类实例化


Grails这样的配置框架之上的约定背后的思想是尽可能遵守约定,这样熟悉约定的任何人都可以立即介入并知道发生了什么。

关于例外情况:

由于映射构造函数,正在发生异常。对于普通groovy类,这不是问题,但grails将域类注册为原型bean。然后它重写元类中的构造函数,以使用bean创建和自动连接机制来获取实例。映射构造函数和自动连接中的某些内容导致在映射设置之前创建一个空的色豆

如果将代码更改为:

Color c = Color.getColor('red')
Mood m = new Mood()
m.color = c
m.save()
例外情况应该消失

你可以考虑为这个特定的用例提交一个文件,但是我不知道GRAILS团队是否会认为这是一个bug或一个设计决定。它肯定没有任何地方被记录在案

关于设计:

在不太了解您的模型的情况下,我同意dmahapatro将数据完整性的责任转移到数据库和GORM约束上。这就是他们的目的

避免这种情况会导致代码中出现异常的使用模式,例如知道如何使用
Color.getColor
,而不是正常的域类实例化


Grails这样的配置框架约定背后的思想是尽可能地遵守约定,这样,熟悉约定的任何人都可以介入并立即知道发生了什么。

为什么不使用枚举进行此类操作呢?因为用户应该能够动态添加新对象。我认为您应该考虑通过数据库约束强制唯一性。是的,我也考虑过这一点,我认为这将是一个非常好的选择可供替代的但我仍然认为,由于它是一种广泛传播的编程模式,在某些情况下,想要控制对象的创建,在groovy中应该是可能的。是什么阻碍了您将
name
作为主键?还有,
Color
如何与
Mood
关联?为什么不使用枚举进行此类操作?因为用户应该能够动态添加新对象。我认为您应该考虑通过数据库约束强制唯一性。是的,我也考虑过这一点,我认为这将是一种替代方法。。但我仍然认为,由于它是一种广泛传播的编程模式,在某些情况下,想要控制对象的创建,在groovy中应该是可能的。是什么阻碍了您将
name
作为主键?而
Color
Mood
有何关联?因此,在这种情况下,这是一种很好的方法。。但这是否意味着您在grails中根本就没有将域类构造函数设置为私有的?@tobi从未使用过或想到过它,因为我使用映射和约束块获得了这种灵活性。@SérgioMichels Buddy,GORM一直是Ray Ban glass,这取决于佩戴它的开发人员。;)。想想Ratpack,计划是在里面放一些像GORM这样的东西。我会是最高兴看到像Gormi这样的东西的开发者