Mẫu Factory
Thuộc phần Lập trình hướng đối tượng trong hành trình R của Coddy. Bài học 43 trên 57.
Factory là một hàm tạo đối tượng để bên gọi không cần biết lớp hoặc hàm khởi tạo của đối tượng đó. Hàm này nhận một mô tả, chẳng hạn như tên kiểu, rồi trả về đối tượng phù hợp:
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")Đầu ra:
circle 12.57
square 4 Với một kiểu mà nó không nhận biết, switch() trả về NULL. Thay vào đó, factory nên dừng và đưa ra thông báo nêu rõ kiểu đó, để lỗi hiển thị ngay tại nơi nó xảy ra:
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)Đầu ra:
unknown shape: hexagonBộ đăng ký lưu các hàm khởi tạo trong một danh sách có tên, nên bản thân hàm factory không bao giờ thay đổi. Ở đây, bộ đăng ký là một môi trường, còn register_shape() thêm một loại mới khi chương trình đang chạy:
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)))Đầu ra:
[1] "rect"
[1] "circle" "rect" Code sử dụng các đối tượng chỉ phụ thuộc vào những thành phần tổng quát, chẳng hạn như area(). Một lớp mới được đăng ký và có phương thức area() sẽ hoạt động với đoạn code đó mà không cần thay đổi gì:
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))))Đầu ra:
[1] 10Thử thách
DễMột bản ghi có thể được xuất ra ở nhiều định dạng. Exporters.R chứa hàm tổng quát export(exporter, record) và phương thức dành cho csv_exporter, trả về các giá trị được nối bằng dấu phẩy. Hãy hoàn thành hai phương thức còn lại trong tệp đó:
json_exporter:{"name": "Ada", "age": "36"};text_exporter:name=Ada; age=36.
Sau đó, viết hàm nhà máy make_exporter(format) trong Factory.R: csv, json hoặc text sẽ tạo ra một danh sách rỗng có lớp csv_exporter, json_exporter hoặc text_exporter, còn mọi định dạng khác sẽ dừng lại với thông báo unknown format: xml (dùng call. = FALSE). Code được cung cấp sẽ đọc tên các trường và giá trị, sau đó đọc tên định dạng, rồi in kết quả xuất của từng định dạng hoặc error: cùng thông báo lỗi.
Hãy viết code vào Exporters.R và Factory.R. main.R chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.
Tự làm thử
source("Exporters.R")
source("Factory.R")
# Đoạn code đầu vào và đầu ra đã có sẵn: bạn giữ nguyên
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 = "")
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về S3
Làm việc với tệpDanh sách với một lớpHàm khởi tạoPhương thức in ra và định dạngTrình xác thực và hàm hỗ trợÔn tập: nhiệt độ4Tính đóng gói trong R
Closure dưới dạng đối tượngMôi trường dưới dạng đối tượngHàm truy cậpBảo vệ trạng tháiÔn tập: đồng hồ tính phí đỗ xe2S3, hàm generic và phương thức
Hàm generic và UseMethodPhương thức mặc địnhPhương thức cho hàm generic cơ sởCơ bản về NextMethodÔn tập: diện tích hình5Các lớp S4
Định nghĩa lớp S4Slot và quyền truy cậpKiểm tra tính hợp lệPhương thức showÔn tập: Danh mục sản phẩmTự luyện tập: Trình biên dịch R online