Menu
Coddy logo textTech

Oluşturucu Kalıbı

Coddy'nin R Journey'sinin Nesne Tabanlı Programlama bölümünün bir parçası. Ders 47 / 57.

Bir oluşturucu, karmaşık bir nesneyi adım adım bir araya getirir ve sonunda build() ile oluşturur. Closure tabanlı bir oluşturucu, parçaları özel değişkenlerde tutar; her adım invisible(self) ile oluşturucunun kendisini döndürür, böylece adımlar zincirlenir ve tek başına çağrılan bir adım hiçbir şey yazdırmaz:

pizza_builder <- function() {
  size <- "medium"
  toppings <- character(0)
  self <- list(
    size = function(s) { size <<- s; invisible(self) },
    add = function(t) { toppings <<- c(toppings, t); invisible(self) },
    build = function() structure(list(size = size, toppings = toppings), class = "pizza")
  )
  self
}
p <- pizza_builder()$size("large")$add("olives")$add("basil")$build()
cat(p$size, "with", paste(p$toppings, collapse = " and "))

Çıktı:

large with olives and basil

build(), nesnenin tamamlanmış olduğunu kontrol edeceğiniz yerdir. Eksik parçalar, yarım oluşturulmuş bir nesne üretmek yerine bir iletiyle işlemi durdurur:

email_builder <- function() {
  to <- NULL
  subject <- ""
  self <- list(
    to = function(x) { to <<- x; invisible(self) },
    subject = function(x) { subject <<- x; invisible(self) },
    build = function() {
      if (is.null(to)) stop("an email needs a recipient", call. = FALSE)
      paste0("To: ", to, " | Subject: ", subject)
    }
  )
  self
}
print(email_builder()$to("ada@x.org")$subject("Hi")$build())
print(tryCatch(email_builder()$subject("Hi")$build(), error = function(e) conditionMessage(e)))

Çıktı:

[1] "To: ada@x.org | Subject: Hi"
[1] "an email needs a recipient"

Aynı fikir, düz değerler ve |> pipe operatörüyle de çalışır. Her adım, şu ana kadarki açıklamayı alan ve güncellenmiş bir kopya döndüren bir işlevdir; son adım ise sonucu oluşturur:

request <- function(url) list(url = url, method = "GET", headers = character(0))
with_method <- function(req, m) { req$method <- m; req }
with_header <- function(req, name, value) { req$headers[name] <- value; req }
build_request <- function(req) {
  c(paste(req$method, req$url), paste0(names(req$headers), ": ", req$headers))
}
r <- request("/users") |> with_method("POST") |> with_header("Accept", "json") |> build_request()
cat(r, sep = "\n")

Çıktı:

POST /users
Accept: json

Bir oluşturucu, bir yapıcıyı çok sayıda isteğe bağlı bağımsız değişkenle değiştirir. Her adım, neyi ayarladığını belirtir ve belirtilmeyen kısımlar varsayılan değerlerini korur:

# okuması zor: TRUE nedir, 3 nedir?
make_report("sales", TRUE, FALSE, 3, "pdf")

# bir builder her değerin ne anlama geldiğini söyler
report_builder("sales")$with_totals()$top(3)$format("pdf")$build()
challenge icon

Görev

Kolay

Kapanış tabanlı query_builder(table) işlevini QueryBuilder.R içinde tamamlayın. Adımları, zincirleme kullanılabilmeleri için oluşturucuyu döndürür:

  • select(cols): gösterilecek sütunlar (varsayılan *);
  • where(cond): bir koşul ekler; birden fazlası AND ile birleştirilir;
  • order_by(col) ve limit(n);
  • build(): SELECT name, age FROM users WHERE age > 30 AND city = 'Rome' ORDER BY name LIMIT 5 gibi sorguyu döndürür ve ayarlanmamış kısımları dışarıda bırakır.

Sağlanan kod tabloyu, ardından select name age, where age > 30, order name veya limit 5 satırlarını okur ve oluşturulan sorguyu yazdırır. Daha sonra tek bir zincir içinde ikinci bir sorgu oluşturur.

Kodunuz QueryBuilder.R içine yazılmalıdır. main.R, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

source("QueryBuilder.R")

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
input <- suppressWarnings(readLines(file("stdin")))
q <- query_builder(input[1])
for (line in input[-1]) {
  p <- strsplit(line, " ")[[1]]
  rest <- paste(p[-1], collapse = " ")
  if (p[1] == "select") q <- q$select(p[-1])
  if (p[1] == "where") q <- q$where(rest)
  if (p[1] == "order") q <- q$order_by(p[2])
  if (p[1] == "limit") q <- q$limit(as.numeric(p[2]))
}
cat(q$build(), "\n", sep = "")
cat(query_builder("logs")$select("msg")$limit(1)$build(), "\n", sep = "")
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Tabanlı Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online R derleyicisi