【问题标题】:Information-hiding in Groovy (using closures? naming conventions?)Groovy 中的信息隐藏(使用闭包?命名约定?)
【发布时间】:2018-11-22 08:00:16
【问题描述】:

这是因为我从 2014 年开始尝试找到this question 的答案,但没有成功。

我不清楚 Groovy 中是否有一些技术可以使用闭包,特别是隐藏信息。我只能说,如果有关于此类技术的信息,那么它就是“信息隐藏”的完美例证:我找不到它!

但是,我认为我现在的理解是,绝对零尝试隐藏信息(或假装,如在 Java 中 - 记住反射技术)。这似乎是设计使然,但也是由于 Groovy 的动态特性的要求。例如,在引用的问题中提到的@CompileStatic 似乎更多的是关于类型检查。

但在 Python 中,例如,有一个约定(我假设仍然使用)使“本应被视为私有的字段”以双下划线开头。我从来没有听到有人谈论过与 Groovy 相关的这个问题。

信息隐藏和封装,或者至少是鼓励有纪律地使用对象的“亲密状态”的惯例,难道不是好事吗?有任何 Groovy 专家愿意发表评论吗?

稍后

daggett 给出的答案在某些方面很有趣,但并不是我的想法。考虑一下:

class Main {
    static main( args ) {
        def sm = new SecurityManager()
        System.setSecurityManager( sm )
        println new Bob().doSomethingProtected()
    }
}


class Bob {
    public doSomethingPublic() {
        "public"
    }
    private doSomethingPrivate() {
        "private"
    }
    protected doSomethingProtected() {
        "protected"
    }
}

...无论Bob 方法中的哪一个被调用,它都会在SecurityManager 未设置时通过,但在设置时失败。它在哪个包中也无关紧要。Bob 是否在子包中(例如)也无关紧要,@PackageScope:只有当Main.main 被赋予@CompileStatic 时,这才有帮助(请参阅参考问题)。 我也不清楚你可以用这种方式设置SecurityManager 做什么:是否可以以某种方式强制执行privateprotected(或包私有)?目前我只是不知道,将不得不调查。

至于另一个建议,它很有趣,但实际上并没有像建议的那样否认“可见性”。您还需要在 A 类中包含以下方法:

def getI() {
    throw new Exception()
}

之后,是的,所有其他类的可见性都被拒绝,无论是否在同一个包中,而且这些“私有”元素甚至对同一类的其他对象都不可见( ! - 与 Java 不同)。从这个意义上说,它确实提供了非常严格的隐私。但对我来说,这也有点像黑客。我不太清楚这个GroovyObjectSupport 类或它的作用,并且必须对其进行调查。最后,实际上给这些字段添加private 修饰符没有什么意义。正如我所说,Groovy 中 private 的唯一功能是在此处拒绝这些字段对 daggett 类 A 的子类的可见性。

在超级严苛的“私有”或“不受限制的公开”之间只有一个严酷的选择,显然与 Java 相比,可见性选择的选择相当“贫困”,在 Java 中,您不仅有 protected,而且还有包私有(主题,是的,是的,当然,使用反射......),并且private 字段对同一类的其他对象可见。

【问题讨论】:

  • 在运行时 groovy 使用反射来调用方法。在java中,您可以使用反射调用受保护和私有方法。如果你想禁用它,你必须使用Security Features in Java。检查ReflectPermission中的suppressAccessChecks权限目标
  • 谢谢...我知道 Java 的这些功能,尽管我从未使用过它们。使用该技术不会干扰 Groovy 的其他功能,与 MOP 等有关吗?不过要去调查...
  • 我已经初步了解了 Java 安全特性。我不确定你如何让 Groovy 使用它们(例如,-Djava.security.manager 不是groovy 命令的有效开关)......我可以问你是否真的为此目的使用了这些功能(信息隐藏),还是只是一种关于如何完成的想法?

标签: groovy encapsulation information-hiding


【解决方案1】:

安全管理器

不要运行来自GroovyConsole 的以下代码。仅来自 groovy 命令行。

def sm = new SecurityManager()
System.setSecurityManager(sm)
//without previous lines the following code will run successfully
println new ByteArrayOutputStream().buf

这会抛出以下异常

Caught: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:109)
        at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:131)
Caused by: java.lang.ExceptionInInitializerError
        at groovy.ui.GroovyMain.run(GroovyMain.java:397)
        at groovy.ui.GroovyMain.process(GroovyMain.java:370)
        at groovy.ui.GroovyMain.processArgs(GroovyMain.java:129)
        at groovy.ui.GroovyMain.main(GroovyMain.java:109)
        ... 6 more
Caused by: java.security.AccessControlException: access denied ("java.util.logging.LoggingPermission" "control")
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
        at java.security.AccessController.checkPermission(AccessController.java:884)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
        at java.util.logging.LogManager.checkPermission(LogManager.java:1586)
        at java.util.logging.Logger.checkPermission(Logger.java:422)
        at java.util.logging.Logger.setUseParentHandlers(Logger.java:1799)
        at org.codehaus.groovy.runtime.StackTraceUtils.<clinit>(StackTraceUtils.java:57)
        ... 10 more

getProperty & setProperty控制访问

class A extends GroovyObjectSupport{
    private int i=555
    private int j=666
    def f(){
        println "i=$i j=$j"
    }
    Object getProperty(String name){
        if(name in ['i'])throw new Exception("Access to property `$name` is denied")
        return super.getProperty(name)
    }
}
def a=new A()
a.f()
println "a.j = ${a.j}"
println "a.i = ${a.i}"

这将允许在课堂外访问成员 j,但不允许访问成员 i

输出:

i=555 j=666
a.j = 666
Exception thrown

java.lang.Exception: Access to property `i` is denied
  ...

【讨论】:

  • 谢谢...在某些方面这是一个有趣的建议,但这不是我的想法。在问题的更新中查看我的 cmets。感谢您展示如何在 groovy 程序中使用 SecurityManager。
【解决方案2】:

我创建了一个编译器扩展,它允许您选择性地或全局地应用编译时检查是否违反封装。此外,您可以在编译时强制执行强类型检查和不变性检查。 https://github.com/stansonhealth/ast-framework

一个例子:

            package com.stansonhealth.ast.encapsulate
            import com.stansonhealth.ast.encapsulate.Encapsulate

            @Encapsulate
            class TestEncapsulationFixture {
                private int i
            }
            
            class TestEncapsulation {
                void foo(TestEncapsulationFixture fixture) {
                    fixture.i++
                    fixture[i]++
                    fixture.i = 0
                    def x = fixture.i
                }
            }

编译器输出:

startup failed:
TestEncapsulation: 14: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 14, column 21.
                       fixture.i++
                       ^

TestEncapsulation: 15: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 15, column 21.
                       fixture[i]++
                       ^

TestEncapsulation: 16: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 16, column 21.
                       fixture.i = 0
                       ^

TestEncapsulation: 17: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 17, column 29.
                       def x = fixture.i
                               ^

4 errors

【讨论】:

    猜你喜欢
    • 2014-01-24
    • 2018-10-31
    • 2013-12-31
    • 2021-08-07
    • 1970-01-01
    • 2012-07-29
    • 2014-03-01
    • 2010-10-14
    相关资源
    最近更新 更多