Ищем решение для Groovy @Mixin, чтобы не нарушать инкапсуляцию

Я хочу использовать аннотацию @Mixin в Groovy, которая делает именно то, что я хочу, за исключением того, что она также смешивает частные методы и поля.

class A {
def private fooA() {
        println("A")
    }
}

@Mixin(A)
class B {
    def fooB() {
        println("B")
   }
}

Если я сейчас запущу этот код

static main(args)
{
    def b = new B()
    println(b.fooA())
    B.metaClass.fooA = {throw new MissingMethodException()};
    println(b.fooA())
}

Сначала он вызывает закрытый метод A.fooA и печатает «A». Затем этот частный метод удаляется и не может быть вызван клиентским классом B из смешанного класса A. Я хотел бы, чтобы все было так с самого начала.

Теперь мой вопрос заключается в том, как я могу добиться этого в общем виде? Я могу расширить аннотацию @Mixin. Проблема в том, что я новичок в Groovy, и на самом деле не так много информации о том, как писать преобразования AST. Новая книга Groovy в действии, в которой о нем есть целая глава, еще не вышла.

Вместо этого я могу использовать @Delegate, но тогда мне нужно объявить переменную для делегированного класса. Это не то, чего я хочу. Я бы предпочел, чтобы я мог просто сказать разработчику, использующему мои материалы, просто аннотировать его класс с помощью @Mixin, чтобы смешать мои материалы, и все. И я могу быть уверен, что частные методы и поля моего класса не могут быть вызваны пользователем, нарушающим внутренний код смешанного класса.

Есть ли у кого-нибудь намек, в каком направлении я должен попытаться сделать это? Спасибо, Оливер.


person OlliP    schedule 23.11.2012    source источник


Ответы (1)


Я думаю, вы натолкнулись на то, что не является сильной стороной Groovy. Поддержка сокрытия закрытых членов имеет проблемы в целом.

В вашем конкретном случае вы могли столкнуться с новой ошибкой (?). Покопавшись, похоже, что преобразование AST для @Mixin вызывает код, который достигает MixinInMetaClass.mixinClassesToMetaClass(). Это делается для того, чтобы не копировать непубличные методы в целевой метакласс (класс вашего класса B); они не отображаются в списке методов на вашем b.metaClass, так что это кажется правильным.

Вызовы b.fooA() будут работать (каким-то образом), пока вы не попытаетесь использовать несуществующее свойство или вызвать несуществующий метод на b. (или позвоните b.metaClass.initialize()). Тогда вы получите жалобы на отсутствие fooA().

Итак, я не уверен, что стал бы тратить слишком много сил на то, чтобы заставить модификаторы доступа работать с Groovy, но если вы продолжите идти по этому пути, я думаю, вам, возможно, придется написать некоторый код инициализации для классов, чтобы они делали что-то вроде вас. сделали выше, или вызовите initialize() или плохое свойство, как я отметил выше. Вы можете попытаться поместить часть этого кода в свой собственный класс ASTTransformation, но я этого не пробовал. Вы можете взять исходный код и посмотреть на org.codehaus.groovy.ast.MixinASTTransformation .

person Brian Henry    schedule 24.11.2012
comment
Привет Брайан, спасибо за ваш ответ. Ну, когда в IDE (я пользуюсь IDEA) всплывает список выбора автодополнения после ввода f. закрытый метод fooA не указан как выбираемый вариант (но есть fooB). Любой разработчик, все еще вызывающий fooA для экземпляра B, уже был как бы предупрежден. Может быть, это достаточно хорошо. В конце концов, я слишком привык к моему предыдущему безопасному миру всего типа ;-). - person OlliP; 24.11.2012