Pattern Factory
Fa parte della sezione Programmazione orientata agli oggetti del percorso R di Coddy. Lezione 43 di 57.
Una factory è una funzione che crea oggetti in modo che chi la chiama non debba conoscere la classe o il suo costruttore. Prende una descrizione, come il nome di un tipo, e restituisce l’oggetto giusto:
area <- function(s) UseMethod("area")
area.circle <- function(s) pi * s$r^2
area.square <- function(s) s$side^2
make_shape <- function(type, size) {
switch(type,
circle = structure(list(r = size), class = "circle"),
square = structure(list(side = size), class = "square"))
}
for (t in c("circle", "square")) cat(t, round(area(make_shape(t, 2)), 2), "\n")Output:
circle 12.57
square 4 Per un tipo che non conosce, switch() restituisce NULL. Una factory dovrebbe invece interrompersi con un messaggio che indichi il tipo, così l’errore viene mostrato nel punto in cui è stato commesso:
make_shape <- function(type, size) {
switch(type,
circle = structure(list(r = size), class = "circle"),
square = structure(list(side = size), class = "square"),
stop("unknown shape: ", type, call. = FALSE))
}
msg <- tryCatch(make_shape("hexagon", 1), error = function(e) conditionMessage(e))
cat(msg)Output:
unknown shape: hexagonUn registro conserva i costruttori in un elenco denominato, così la factory stessa non cambia mai. Qui il registro è un ambiente e register_shape() aggiunge un nuovo tipo mentre il programma è in esecuzione:
registry <- new.env()
register_shape <- function(name, maker) assign(name, maker, envir = registry)
make_shape <- function(name, ...) {
if (!exists(name, envir = registry, inherits = FALSE)) stop("unknown shape: ", name, call. = FALSE)
get(name, envir = registry)(...)
}
register_shape("circle", function(r) structure(list(r = r), class = "circle"))
register_shape("rect", function(w, h) structure(list(w = w, h = h), class = "rect"))
print(class(make_shape("rect", 2, 3)))
print(sort(ls(registry)))Output:
[1] "rect"
[1] "circle" "rect" Il codice che usa gli oggetti dipende solo dai generici, come area(). Una nuova classe registrata che dispone di un metodo area() funziona con quel codice senza apportare alcuna modifica:
registry <- new.env()
register_shape <- function(name, maker) assign(name, maker, envir = registry)
make_shape <- function(name, ...) get(name, envir = registry)(...)
area <- function(s) UseMethod("area")
total_area <- function(shapes) sum(vapply(shapes, area, numeric(1)))
register_shape("square", function(a) structure(list(a = a), class = "square"))
area.square <- function(s) s$a^2
register_shape("tri", function(b, h) structure(list(b = b, h = h), class = "tri"))
area.tri <- function(s) s$b * s$h / 2
print(total_area(list(make_shape("square", 2), make_shape("tri", 4, 3))))Output:
[1] 10Sfida
FacileUn record può essere esportato in diversi formati. Exporters.R contiene la funzione generica export(exporter, record) e il metodo per csv_exporter, che restituisce i valori uniti da virgole. Completa gli altri due metodi:
json_exporter:{"name": "Ada", "age": "36"};text_exporter:name=Ada; age=36.
Poi scrivi la factory make_exporter(format) in Factory.R: csv, json o text restituiscono una lista vuota con la classe csv_exporter, json_exporter o text_exporter, mentre qualsiasi altro formato si interrompe con unknown format: xml (usa call. = FALSE). Il codice fornito legge i nomi dei campi e i valori, poi i nomi dei formati, e stampa ogni esportazione oppure error: e il messaggio.
Il tuo codice va in Exporters.R e Factory.R. main.R contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
source("Exporters.R")
source("Factory.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
fields <- strsplit(input[1], ",")[[1]]
values <- strsplit(input[2], ",")[[1]]
record <- setNames(values, fields)
for (fmt in input[-(1:2)]) {
out <- tryCatch(export(make_exporter(fmt), record), error = function(e) paste("error:", conditionMessage(e)))
cat(out, "\n", sep = "")
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Nozioni di base su S3
Lavorare con i fileListe con una classeFunzioni costruttriciMetodi di stampa e formattazioneValidatori e funzioni di supportoRipasso - Temperature4Incapsulamento in R
Chiusure come oggettiAmbienti come oggettiFunzioni di accessoProteggere lo statoRiepilogo - Parcometro2Generics e metodi S3
Generics e UseMethodMetodi predefinitiMetodi per i generics di baseNozioni di base su NextMethodRiepilogo - Aree delle forme5Classi S4
Definire le classi S4Slot e accessoControlli di validitàMetodi showRiepilogo - Catalogo prodotti8Classi di riferimento
Definizione delle classi di riferimentoMetodi e aggiornamenti dei campiSemantica della copiaEreditarietà e callSuperRiepilogo - coda di attività11Progetto: Gestione della biblioteca
Libri e iscrittiPrestito dei libriEsercitati da solo: Compilatore R online