如何使用Grails服务层实现多态行为

如何使用Grails服务层实现多态行为,grails,service,polymorphism,service-layer,Grails,Service,Polymorphism,Service Layer,我在谷歌上搜索了很多这个话题,但我只找到了Stackoverflow帖子。假设我有一个简单的域模型层次结构: class Furniture{} class Table extends Furniture{} class Sideboard extends Furniture{} 我如何实现一个名为position的服务方法,该方法在不使用instanceof或带有.class.name的if语句的情况下为相应的对象类型调用,同时仍然为各个域类维护分离的服务类 我真的很喜欢这个答案,但这里所有

我在谷歌上搜索了很多这个话题,但我只找到了Stackoverflow帖子。假设我有一个简单的域模型层次结构:

class Furniture{}
class Table extends Furniture{}
class Sideboard extends Furniture{}
我如何实现一个名为
position
的服务方法,该方法在不使用
instanceof
或带有
.class.name
的if语句的情况下为相应的对象类型调用,同时仍然为各个域类维护分离的服务类

我真的很喜欢这个答案,但这里所有的方法都打包在一个服务中。我认为服务类可能会增长过大,这取决于要执行的操作的数量或类层次结构的深度(我知道,无论如何都应该避免后者,但仍然如此)

我可以想出两种方法来实现这一点,但他们都似乎破碎和黑客

选项1:访问应用程序上下文

class FurnitureService{
    def grailsApplication
    void position(Furniture furniture){
       grailsApplication.getMainContext().getBean(Introspector.decapitalize(furniture.class.simpleName) +  'Service').position(furniture)
    }
}
class TableService{
    void position(Table table){
        println "table positioned"
    }
}
class SideboardService{
    void position(Sideboard sideboard){
        println "sideboard positioned"
    }
}
我真的很讨厌这个解决方案,因为它根本没有使用DI

选项2:使用反射获得正确的注入服务类

class FurnitureService{
    def tableService
    def sideboardService
    void position(Furniture furniture){   
        furniture.class.getDeclaredField(Introspector.decapitalize(furniture.class.simpleName) + 'Service').get(this).position(furniture)
    }
}
class TableService{
    void position(Table table){
        println "table positioned"
    }
}
class SideboardService{
    void position(Sideboard table){
        println "sideboard positioned"
    }
}
不知道第一个选择是更好还是更糟糕。我不喜欢使用反射。在传统的OO方式中,我只会重写一个抽象方法。必须有一个最佳实践惯例来处理这个问题


我想我现在用这些方法让我的生活变得太艰难了。谁能给我一个简洁明了的“业务标准”解决方案?如果重定向到grails文档或教程(如果有人认为这是必要的话),我不会生气。

如果您拥有来自不同服务的所有给定方法,您的应用程序的传入类型可以决定使用哪一种。有不同的方法可以将您的所有服务混合到一个服务中

您可以使用一个,让它决定传入的类型。例如:

class Furniture{}
class Table extends Furniture{}
class Sideboard extends Furniture{}
class FurnitureService{
    @Delegate TableService tableService
    @Delegate SideboardService sideboardService
}
class TableService{
    String position(Table table){
        return 'table'
    }
}
class SideboardService{
    String position(Sideboard sideboard){
        return 'sideboard'
    }
}

def s = new FurnitureService()
assert s.position(new Table())=='table'
assert s.position(new Sideboard())=='sideboard'
基本相同,如果您的groovy/grails版本足够新,可以通过以下方式完成:


这当然是groovy的神奇之处,它只是将特殊服务组合成通用服务。简单的事实是,传入的参数将决定调用哪个专用方法,这是这里的关键。

谢谢!还没有在grails中尝试过,但它在groovyconsole中工作,是一个很好的替代方案。您所说的“仅用于测试,应自动连接”是什么意思?你是说它应该由grails/spring自动连接吗?在grails中会是什么样子,比如
@Delegate def tableService
?@nst1nctz是这样的。只需去掉
=新的…
部分。但是你必须使用一个类型,否则
@Delegate
将无法工作!一般来说,它应该可以工作,因为委托只生成与服务中的方法相匹配的方法,并调用委托所针对的对象中的原始方法。这不重要,如果风险值是在第一时间注入的。。。但是除了groovy magic之外,grails magic也发生在那里,所以没有人知道;)是的,有时候圣杯的魔法对我来说就像是一堆邪恶的咒语,尽管我喜欢它的惯例和易用性。但无论如何,如果你的答案有效的话,我会把它标记为正确的。如果不是,我将为groovy打开另一个问题,您可以在这里回答,这样我就可以在这里将其标记为正确。非常感谢;)@nst1nctz无需匆忙。请让我知道,如果它在grails中不起作用,我将在那里试用它。嗯,委托注释在java.lang.Object或groovy.lang.Object上不起作用。我想我必须在grails中使用def。由于我使用groovy 2.3,现在我将尝试这些特性。
class Furniture{}
class Table extends Furniture{}
class Sideboard extends Furniture{}
class FurnitureService implements TableService, SideboardService {}
trait TableService{
    String position(Table table){
        return 'table'
    }
}
trait SideboardService{
    String position(Sideboard sideboard){
        return 'sideboard'
    }
}

def s = new FurnitureService()
assert s.position(new Table())=='table'
assert s.position(new Sideboard())=='sideboard'