R: используйте активную привязку в генераторе объектов для условного добавления нового класса к объектам R6

#r #oop #inheritance #r6

#r #ооп #наследование #r6

Вопрос:

У меня есть простой генератор объектов R6:

 thing <- R6Class("youngThing",
                 private = list(
                   ..age = 0),
                 active = list(
                   age = function(){
                     private$..age <- private$..age   1
                     private$..age
                   }
                 )
)
  

Это дает мне простой объект R6, который ..age увеличивается на 1 при каждом вызове активного age поля:

 a_thing <- thing$new()

a_thing$age
# [1] 1
  

Я хочу, чтобы класс объекта a_thing изменялся с учетом порогового значения частного поля ..age , например:

 class(a_thing)
# [1] "youngThing" "R6"

for(timestep in 1:10){
  if(a_thing$age >5 amp; ! inherits(a_thing, "olderThing")){
    class(a_thing) <- c("olderThing", class(a_thing))
  }
}

class(a_thing)
# [1] "olderThing" "youngThing" "R6" 
  

Однако я хочу, чтобы это происходило внутри объекта. Есть ли способ включить это в качестве активной привязки в генератор объектов, чтобы любой созданный из него объект имел встроенную эту функциональность?

ПРИМЕЧАНИЕ. Предпочтительно, чтобы пороговый класс добавлялся к объекту; что он не заменяет существующие классы.

Комментарии:

1. Изменение класса кажется немного странным выбором дизайна. Почему бы просто не иметь общедоступный is_old логический флаг, который можно запрашивать по мере необходимости?

2. Я ожидаю, что будут некоторые ответы, которые сделают это возможным технически, но дважды подумайте о том, что это значит с точки зрения дизайна. Что, если вы присвоите объект переменной, затем вызовете метод, чтобы класс изменился, а затем вызовите функцию, которая ожидает старый класс с объектом. Это нарушает некоторые предположения, обычно сделанные относительно (неизменяемого) класса объекта, и может привести к проблемам позже.

3. @AllanCameron Привет, спасибо за комментарий. В ситуации, когда один объект является одним человеком, я могу использовать универсальный метод S3 для реализации другого метода в зависимости от класса (возраста) объекта (человека).

4. @jayb или у вас может быть один метод, который проверяет поле age и ведет себя соответствующим образом?

Ответ №1:

Вы можете изменить класс self .

 library(R6)

thing <- R6Class(
  "youngThing",
  private = list(..age = 0),
  active = list(
    age = function() {
      private$..age <- private$..age   1

      if(private$..age > 5 amp;amp; !inherits(self, "olderThing")){
        class(self) <- c("olderThing", class(self))
      }
      private$..age
    }
  )
)
  

a_thing пока имеет исходный класс age <= 5 .

 a_thing <- thing$new()

a_thing$age; a_thing$age; a_thing$age; a_thing$age; a_thing$age
#> [1] 2
#> [1] 3
#> [1] 4
#> [1] 5

class(a_thing)
#> [1] "youngThing" "R6" 
  

Затем он обновляется после завершения 5 .

 a_thing$age
#> [1] 6

class(a_thing)
#> [1] "olderThing" "youngThing" "R6"