2013-10-07 5 views
7

Обычно я программирую по функциям «инстинктивно», но моя текущая проблема может быть легко решена объектами, поэтому я продолжу этот метод.есть конструктор объекта в rebol

Выполнение этого действия, я пытаюсь найти способ дать объекту метод-конструктор, эквивалент init() в python, например.

Я просмотрел документацию http://www.rebol.com/docs/core-fr/fr-index.html, но я не нашел ничего подходящего.

ответ

3

На самом деле, еще раз прочитав документацию Rebol сердечника (я просто следовал старому доброму совету: «Прочитайте французское руководство»), есть еще один способ реализовать конструктор, достаточно прост:

http://www.rebol.com/docs/core-fr/fr-rebolcore-10.html#section-8

конечно, это также английское руководство:

http://www.rebol.com/docs/core23/rebolcore-10.html#section-7

=>

Другой пример использования переменной само является функцией, которая клонирует себя:

person: make object! [ 
    name: days-old: none 
    new: func [name' birthday] [ 
     make self [ 
      name: name' 
      days-old: now/date - birthday 
     ] 
    ] 
] 

lulu: person/new "Lulu Ulu" 17-May-1980 

print lulu/days-old 
7366 

Я нахожу это очень удобно, и таким образом, конструктор находится в пределах объекта. Этот факт делает объект более самодостаточным.

Я просто реализован, успешно в течение некоторого геологического материала, и он хорошо работает:

>> source orientation 
orientation: make object! [ 
    matrix: [] 
    north_reference: "Nm" 
    plane_quadrant_dip: "" 
    new: func [{Constructor, builds an orientation object! based on a measurement, as given by GeolPDA device, a rotation matrix represented by a suite of 9 values} m][ 
     make self [ 
      foreach [a b c] m [append/only matrix to-block reduce [a b c]] 
      a: self/matrix/1/1 
      b: self/matrix/1/2 
      c: self/matrix/1/3 
      d: self/matrix/2/1 
      e: self/matrix/2/2 
      f: self/matrix/2/3 
      g: self/matrix/3/1 
      h: self/matrix/3/2 
      i: self/matrix/3/3 
      plane_normal_vector: reduce [matrix/1/3 
       matrix/2/3 
       matrix/3/3 
      ] 
      axis_vector: reduce [self/matrix/1/2 
       self/matrix/2/2 
       self/matrix/3/2 
      ] 
      plane_downdip_azimuth: azimuth_vector plane_normal_vector 
      plane_direction: plane_downdip_azimuth - 90 
      if (plane_direction < 0) [plane_direction: plane_direction - 180] 
      plane_dip: arccosine (plane_normal_vector/3) 
      case [ 
       ((plane_downdip_azimuth > 315) or (plane_downdip_azimuth <= 45)) [plane_quadrant_dip: "N"] 
       ((plane_downdip_azimuth > 45) and (plane_downdip_azimuth <= 135)) [plane_quadrant_dip: "E"] 
       ((plane_downdip_azimuth > 135) and (plane_downdip_azimuth <= 225)) [plane_quadrant_dip: "S"] 
       ((plane_downdip_azimuth > 225) and (plane_downdip_azimuth <= 315)) [plane_quadrant_dip: "W"] 
      ] 
      line_azimuth: azimuth_vector axis_vector 
      line_plunge: 90 - (arccosine (axis_vector/3)) 
     ] 
    ] 
    repr: func [][ 
     print rejoin ["Matrix: " tab self/matrix 
      newline 
      "Plane: " tab 
      north_reference to-string to-integer self/plane_direction "/" to-string to-integer self/plane_dip "/" self/plane_quadrant_dip 
      newline 
      "Line: " tab 
      rejoin [north_reference to-string to-integer self/line_azimuth "/" to-string to-integer self/line_plunge] 
     ] 
    ] 
    trace_te: func [diagram [object!]][ 
     len_queue_t: 0.3 
     tmp: reduce [ 
      plane_normal_vector/1/(square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2)))) 
      plane_normal_vector/2/(square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2)))) 
     ] 
     O: [0 0] 
     A: reduce [- tmp/2 
      tmp/1 
     ] 
     B: reduce [tmp/2 0 - tmp/1] 
     C: reduce [tmp/1 * len_queue_t 
      tmp/2 * len_queue_t 
     ] 
     L: reduce [- axis_vector/1 0 - axis_vector/2] 
     append diagram/plot [pen black] 
     diagram/trace_line A B 
     diagram/trace_line O C 
     diagram/trace_line O L 
    ] 
] 
>> o: orientation/new [0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778] 
>> o/repr 
Matrix:  0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778 
Plane: Nm120/39/S 
Line: Nm299/0 

Еще одним преимуществом этого способа является то, что переменные, определенные «нового» метода непосредственно относится к «экземпляра» объекта (Я столкнулся с некоторыми проблемами, с другими методами, говоря о себе/иногда, вынужденным инициализировать переменные или нет).

6

Там нет специальной функции конструктора в Rebol, но есть возможность писать специальный код инициализации, если вам это нужно на создание объекта в спецификации блока. Например:

a: context [x: 123] 

b: make a [ 
    y: x + 1 
    x: 0 
] 

Таким образом, если вы определили свою собственную функцию «конструктор» в соответствии с соглашением в базовом объекте, вы можете называть его спецификации блока по созданию. Если вы хотите сделать это автоматически, вы можете обернуть, что в функции, например:

a: context [ 
    x: 123 
    init: func [n [integer!]][x: n] 
] 

new-a: func [n [integer!]][make a [init n]] 

b: new-a 456 

Более надежный (но немного длиннее) версии нового-а что позволит избежать возможного столкновения переданных аргументов в инициализации с собственными словами объекта будет:

new-a: func [n [integer!] /local obj][ 
    also 
     obj: make a [] 
     obj/init n 
] 

Вы также можете написать более общей новой функции, которая будет принимать базовый объект в качестве первого аргумента и автоматически вызывать функцию конструктора-на-конвенции после Clon что объект, но вспомогательные аргументы конструктора в общем случае более сложны.

Помните, что объектная модель Rebol является прототипом на основе (по сравнению с классовым в Python и других языках объектно-ориентированного программирования), поэтому функция «конструктор» получает дублируется для каждого нового объекта, созданного. Вы можете избежать такой стоимости, если вы создаете огромное количество объектов.

+0

Да, вы оба в конечном итоге с очень похожими решениями. init или new? вот вопрос, чтобы назвать метод конструктора ... Конечно, если нужно создать большое количество объектов, таких методов следует обязательно избегать. В моей нынешней проблематике я действительно думал о нескольких объектах, даже не о дюжине. – Pierre

5

Насколько я знаю, формального метода/соглашения для использования конструкторов объектов, таких как init(), нет. Существует, конечно, встроенный метод построения производных объектов:

make prototype [name: "Foo" description: "Bar"] 
    ; where type? prototype = object! 

Мое лучшее предложение было бы определить функцию, которая инспектирует объект для метода конструктора, а затем применяет этот метод, вот одна такая функция, что я «ве proposed previously:

new: func [prototype [object!] args [block! none!]][ 
    prototype: make prototype [ 
     if in self 'new [ 
      case [ 
       function? :new [apply :new args] 
       block? :new [apply func [args] :new [args]] 
      ] 
     ] 
    ] 
] 

использование довольно просто: если объект-прототип имеет значение new, то он будет применен в строительстве производного объекта:

thing: context [ 
    name: description: none 
    new: [name: args/1 description: args/2] 
] 

derivative: new thing ["Foo" "Bar"] 

Обратите внимание, что этот подход работает как в Rebol 2, так и 3.

+0

ok: все, что нам нужно, является подходящим соглашением для метода конструктора в объекте, если это необходимо. – Pierre

3

Я пытаюсь выяснить, как работает OO в REBOL. На самом деле это прототип. Вчера я наткнулся на этой странице, которая вдохновила меня на классическую модель OO ниже, без дублирования функций:

;---- Generic function for class or instance method invocation ----; 
invoke: func [ 
    obj [object!] 
    fun [word!] 
    args [block!] 
][ 
    fun: bind fun obj/.class 
    ;---- Class method names start with a dot and instance method names don't: 
    unless "." = first to-string fun [args: join args obj] 
    apply get fun args 
] 

;---- A class definition ----; 
THIS-CLASS: context [ 
    .class: self       ; the class refers to itself 

    ;---- Class method: create new instance ----; 
    .new: func [x' [integer!] /local obj] [ 
     obj: context [x: x' .class: none] ; this is the object definition 
     obj/.class: self/.class   ; the object will refer to the class 
              ; it belongs to 
     return obj 
    ] 

    ;---- An instance method (last argument must be the instance itself) ----; 
    add: func [y obj] [ 
     return obj/x + y 
    ] 
] 

Тогда вы можете сделать это:

;---- First instance, created from its class ----; 
this-object: THIS-CLASS/.new 1 
print invoke this-object 'add [2] 

;---- Second instance, created from from a prototype ----; 
that-object: this-object/.class/.new 2 
print invoke that-object 'add [4] 

;---- Third instance, created from from a prototype in another way ----; 
yonder-object: invoke that-object '.new [3] 
print invoke yonder-object 'add [6] 

;---- Fourth instance, created from from a prototype in a silly way ----; 
silly-object: yonder-object/.class/.class/.class/.class/.new 4 
print silly-object/.class/add 8 silly-object 
print this-object/.class/add 8 silly-object 
print THIS-CLASS/add 8 silly-object 

(Он работает в REBOL 2, и печатает 3, 6, 9, 12, 12, 12 подряд.) Вряд ли накладные расходы. Вероятно, не составит труда найти десяток других решений. Именно это и есть настоящая проблема: слишком много способов сделать это. (Может быть, нам лучше использовать LoyalScript.)