DecoratorClass: Create an abstract R6 Class

Description Details References Examples

View source: R/DecoratorClass.R

Description

Creates a decorator R6 class by placing a thin wrapper around R6::R6Class which allows the constructed class to inherit the fields and methods of the given object.

Details

The decorator design pattern allows methods to be added to an object without bloating the interface with too many methods on construction and without causing large inheritance trees. A decorator class contains fields/methods that are 'added' to the given object in construction, this is made clearer in examples.

There are three possibilities when trying to decorate an object with a field/method that already exists:

  1. exists = "error" (default) - This will throw an error and prevent the object being decorated

  2. exists = "skip" - This will decorate the object with all fields/methods that don't already exist

  3. exists = "overwrite" - This will decorate the object with all fields/methods from the decorator and overwrite ones with the same name if they already exist

Decorators are currently not cloneable.

All arguments of R6::R6Class can be used as usual, see full details at R6::R6Class.

References

Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1996). Design Patterns: Elements of Reusable Software. Addison-Wesley Professional Computing Series (p. 395).

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
library(R6)

## Create two decorators
# Works with active bindings...
dec1 <- DecoratorClass("dec1", active = list(hi = function() "Hi World"))
# And public fields...
dec2 <- DecoratorClass("dec2", public = list(goodbye = "Goodbye World"))

## Create an object to decorate
oop <- ooplah$new()
oop$hello()

## Decorate with dec1 by constructing dec1 with object oop:
dec_oop <- dec1$new(oop)
## We have all original methods from oop
dec_oop$hello()
# It's inherited methods
dec_oop$init
# And now decorated methods
dec_oop$hi

## We can decorate again
redec_oop <- dec2$new(dec_oop)
redec_oop$hello()
redec_oop$init
redec_oop$hi
# And now
redec_oop$goodbye

# Notice the class reflects all decorators, the original object and parents,
#  and adds the 'Decorator' class
class(redec_oop)

## Decorators also work with inheritance
parent_dec <- DecoratorClass("parent_dec",
  public = list(hi = function() "Hi!"))
child_dec <- DecoratorClass("child_dec", inherit = parent_dec)
dec_oop <- child_dec$new(ooplah$new())
dec_oop$hi()

## Three possibilities if the method/field name already exists:
oop <- ooplah$new()
exists_dec <- DecoratorClass("exists_dec",
  public = list(hello = function() "Hi!"))

# 1. error (default)
## Not run: 
exists_dec$new(oop)
exists_dec$new(oop, exists = "error")

## End(Not run)

# 2. skip
oop$hello()
exists_dec$new(oop, exists = "skip")$hello()

# 3. overwrite
oop$hello()
exists_dec$new(oop, exists = "overwrite")$hello()

## Cloning
# Note that by default the decorated object is not cloned
dec <- DecoratorClass("dec", active = list(hi = function() "Hi World"))
dec_oop <- dec$new(oop)
dec_oop$logically
oop$logically <- FALSE
dec_oop$logically

ooplah documentation built on Sept. 10, 2021, 5:08 p.m.