R6: Pertimbangkan untuk menambahkan metode/bidang statis

Dibuat pada 24 Jun 2015  ·  8Komentar  ·  Sumber: r-lib/R6

Jika sebuah generator bernama MyClass , alangkah baiknya jika dapat memanggil MyClass$foo() . Dan di dalam metode, Anda akan memanggil class$foo() .

feature

Komentar yang paling membantu

+1 pada metode statis

Semua 8 komentar

Satu hal yang perlu dipertimbangkan adalah jika objek R6 menyimpan referensi ke generatornya, maka objek tersebut membawa generator saat disimpan.

@wch Saya tidak berpikir ini diinginkan, maksud saya harus menjaga fungsi generator, dengan lingkungannya, untuk setiap objek.

Ya, mungkin lebih mudah bagi seseorang untuk membuat lingkungan atau daftar baru dengan beberapa fungsi di dalamnya. Anda mungkin memiliki objek kelas String , dan kemudian daftar terpisah dengan beberapa fungsi di dalamnya, seperti StringUtils . Kemudian metode di String bisa memanggil StringUtils$foo() .

+1 pada metode statis

Bagaimana kalau tidak menyimpan metode/variabel statis untuk objek? Jika pengguna membutuhkan metode statis, mereka hanya akan menggunakan generator. Jika suatu objek membutuhkan metode statis, mereka dapat merujuk ke generator secara eksplisit.

Generator bukan lingkungan, sehingga tidak memiliki semantik referensi saat ini. Tapi mungkin kita bisa mengatasinya entah bagaimana, misalnya tetap menggunakan anggota yang merupakan lingkungan: generator$static <- new.env() .

Saat ini saya menggunakan _constants_ statis, yang termasuk dalam kelas. Saya hanya menempelkannya ke generator: generator$myconstant <- "foo" Saya kira saya mungkin juga meletakkannya di objek, di belakang pengikatan aktif, atau sebagai anggota pribadi dengan metode get....

Hanya berpikir keras, sungguh.

Menggunakan lingkungan untuk meniru bidang statis, seperti yang disarankan oleh @gaborcsardi , sepertinya ide yang bagus. Sangat berguna untuk dapat membedakan bidang public static dan bidang private static , seperti yang Anda lakukan di Java atau C#.

Jadi menurut saya, harus ada lingkungan statis di dalam self , dan yang lain di dalam private . Kemudian Anda dapat mengakses bidang ini menggunakan self$static dan private$static , yang cukup dekat dengan sintaks Java/C#, sehingga memudahkan orang yang berasal dari latar belakang OOP tradisional untuk memahami.

Solusi saya saat ini adalah mendefinisikan lingkungan bernama static di dalam public dan/atau private sesuai kebutuhan.

library(R6)
rtc_factory <- R6Class(
  "ReferenceTestClass",
  public = list(
    static = new.env(),
    instance = list(),
    show = function() {
      message("Static fields:")
      print(capture.output(ls.str(self$static)))
      message("Instance fields:")
      print(capture.output(ls.str(self$instance)))
    }
  )
)

rtc_object1 <- rtc_factory$new()
rtc_object1$static$x <- 1
rtc_object1$instance$a <- 2

rtc_object2 <- rtc_factory$new()
rtc_object2$static$y <- 3
rtc_object2$instance$b <- 4

rtc_object1$show()
## Static fields:
## [1] "x :  num 1" "y :  num 3"
## Instance fields:
## [1] "a :  num 2"
rtc_object2$show()
## Static fields:
## [1] "x :  num 1" "y :  num 3"
## Instance fields:
## [1] "b :  num 4"

Untuk membuat fitur ini lebih mudah bagi pengguna, saya pikir akan lebih baik jika lingkungan static ini dibuat secara otomatis oleh fungsi R6Class .

Untuk anggota statis, berikut adalah beberapa hal yang perlu diketahui. Dan kemudian ada juga masalah memastikan bahwa itu benar-benar bisa diimplementasikan.

(1) Bagaimana mereka diakses dari luar kelas?

Akan menyenangkan untuk melakukan Class$method() (di mana Class adalah objek generator R6), tetapi saya pikir sudah terlambat untuk itu pada saat ini, karena objek Class sudah memiliki banyak anggota yang mungkin sudah digunakan orang. Alternatif yang lebih bertele-tele adalah Class$static$method() , yang seharusnya aman.

(2) Bagaimana mereka diakses dari metode statis lainnya?

Beberapa kemungkinan: method() , static$method() , atau Class$static$method() .

(3) Bagaimana mereka diakses dari dalam objek R6?

Beberapa kemungkinan: method() , static$method() , self$static$method() , atau Class$static$method() .

(4) Haruskah ada anggota statis publik dan swasta?

Saya akan condong ke arah hanya memiliki anggota statis publik, untuk kesederhanaan.

(5) Haruskah mereka bisa berubah? Dan haruskah ini dapat dikonfigurasi?

Saya pikir defaultnya adalah set item statis harus dikunci, sama seperti public dan private .

(6) Bagaimana seharusnya warisan bekerja?

Mungkin tidak memiliki warisan sama sekali?


Hal-hal yang ingin saya hindari:

(1) Menanamkan seluruh objek generator dalam objek instan. Instance tidak boleh berisi referensi apa pun (langsung atau tidak langsung) ke generator.

(2) Masalah kompatibilitas build-time/run-time. Misalnya, misalkan paket A 1.0 memiliki kelas AC dengan AC$static$x=1 , dan Anda memiliki paket B yang membuat dan menyimpan objek a , di mana a <- AC$new() . Kemudian Anda memutakhirkan paket A ke 2.0, dan memiliki AC$static$x=2 . Pada titik ini, jika sesuatu dalam paket B mengakses AC$static$x , tampaknya jelas bahwa Anda harus mendapatkan 2 . Tetapi jika metode dalam objek a mengakses self$static$x , haruskah itu mendapatkan 1 atau 2 ? Saya pikir jawabannya adalah Anda harus mendapatkan 2 , tetapi kemudian self$static harus terikat secara dinamis. Ini dimungkinkan dengan menggunakan pengikatan aktif. Masalah build-time/run-time ini adalah masalah nyata yang pernah saya alami beberapa kali di masa lalu dalam berbagai bentuk, dan saya telah merancang R6 untuk menghindarinya sejauh ini.


Dengan contoh rct_factory Anda, sepertinya bidang static sebagian besar ada untuk berbagi nilai di antara instance kelas. Saya cukup yakin bahwa Anda dapat mengalami masalah yang terkait erat dengan waktu build/run yang saya jelaskan di atas.

Misalkan paket A memiliki rtc_factory , dan sebuah instance, rtc_object_a . Kemudian Anda menginstal paket B, yang berisi sebuah instance, rtc_object_b . Bergantung pada bagaimana paket tersebut dibuat, instance mungkin tidak berbagi lingkungan static yang sama. Saya 100% yakin bahwa jika ini adalah perintahnya, static itu tidak akan dibagikan:

  • Instal paket A 1.0
  • Instal paket B
  • Instal ulang paket A 1.0 (atau tingkatkan ke A 2.0)

Jika Anda menggunakan platform yang menginstal dari paket biner, ada lebih banyak tempat untuk kesalahan.


Saya belum memiliki jawabannya, tetapi menulis ini setidaknya membantu memperjelas dalam pikiran saya apa masalahnya ...

Tulisan yang bagus!

Setelah membacanya, saya merasa bahwa ini tidak cocok dengan R6, dan/atau tidak mungkin untuk diterapkan dengan baik.

Ini mengatakan, akan menyenangkan untuk memiliki cara yang "disarankan" untuk berbagi informasi di antara instance kelas. Meskipun ini bisa sesederhana "meletakkannya di lingkungan dalam namespace paket".

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

rappster picture rappster  ·  3Komentar

kenarab picture kenarab  ·  8Komentar

mattwarkentin picture mattwarkentin  ·  7Komentar

paulstaab picture paulstaab  ·  3Komentar

rappster picture rappster  ·  11Komentar