我们想为Samsung Groovy SmartThings实现基础架构。当然,基础结构的主要部分是使用相应的方法为每个设备实现不同的类。 例如,对于锁的设备,我们假设我们有一个锁类,带有方法lock()和unlock()。这里的问题是我们在Groovy的SmartThings应用程序之一中拥有这部分代码:
def presence(evt)
{
if (evt.value == "present") {
//Somecode
lock1.unlock()
}
else {
//Somecode
lock1.lock()
}
}
因此,很可能lock1是类锁的对象,而lock()和unlock()是该类的方法。这是东西: 使用lock1 [0] .unlock()命令可解锁#0号门锁,但使用lock1.unlock()命令可解锁所有门锁。
这里的问题是如何创建类?如果lock1是对象列表,那么如何拥有类似lock1.unlock()的命令。
这里的要点是,两个对象都应具有相同的名称lock1,并且这两个方法都是名为lock()的相同方法。
谢谢。
答案 0 :(得分:1)
在这里看到的“问题”是Groovy中的spread operator(隐式)。
表达式
cars*.make
等效于cars.collect{ it.make }
。当引用的属性不是包含列表的属性时,Groovy的GPath表示法允许使用捷径,在这种情况下,它会自动传播。在上述情况下,可以使用表达式cars.make
,尽管通常建议保留显式扩展点运算符。
(此处的示例涉及GPath,但列表,地图等也是如此)
因此,在这种情况下,lock1.unlock()
是lock1*.unlock()
。 (动态)Groovy将看到,列表上没有unlock()
方法,只是散开了。
对于“因此,很可能lock1是类锁的对象” ,这将给您带来噩梦。不要猜测-找出答案。您可以println(lock1.inspect())
来获取详细信息,希望该类的作者具有预见性,可以添加一个有用的toString()
方法。检查文档,函数返回什么,然后从中分配locks1
。使用工具,它会告诉您类型(IDE,调试器...)。
对于开发人员而言,更好的命名方式有助于:
// BAD naming
def locks1 = smartThings.getAll(Lock, clientId)
// better naming, add the type if it helps you or your IDE
Collection<Lock> allLocks = smartThings.getAll(Lock, clientId)
现在,如果您打电话给allLocks.lock()
,事情就更明显了。
要防止隐式传播运算符,可以在groovy脚本中使用静态编译。例如:
class Lock {
def lock() { println "lock" }
def unlock() { println "unlock" }
}
@groovy.transform.CompileStatic
class X {
public static main() {
[new Lock()].lock()
}
}
无法编译:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
x.groovy: 9: [Static type checking] - Cannot find matching method java.util.List#lock(). Please check if the declared type is correct and if the method exists.
@ line 9, column 3.
[new Lock()].lock()
^
1 error
使用显式扩展运算符([new Lock()]*.lock()
)进行编译。
答案 1 :(得分:0)
您在这里有2个选择:
1)使用Groovy的spread运算符在列表的每个元素上调用该方法:
List lock1 = [.....]
lock1.*lock()
2)使Lock
类扩展或包含元素列表,并向其添加类级方法:
class Lock {
List locks
def lock() {
locks.*lock()
}
// this method allows for calls like lock1[42].lock()
def getAt( int ix ) {
locks[ ix ]
}
}
实际上,对于物联网设备而言,继承是有害的。