Strategyパターン
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 45/57。
ストラテジーパターンはアルゴリズムを置き換え可能にします。それを必要とするコードは、アルゴリズムを引数として受け取ります。Rでは関数は値なので、ストラテジーは渡される関数であり、呼び出し側がどれを使うかを選択します。
no_discount <- function(total) total
half_price <- function(total) total / 2
checkout <- function(total, discount = no_discount) {
paste("pay", discount(total))
}
print(checkout(80))
print(checkout(80, half_price))出力:
[1] "pay 80"
[1] "pay 40"名前付きの戦略リストを使うと、実行時にプログラムが名前で戦略を選択できます。たとえば、ユーザー入力から選択する場合です。
pricing <- list(
regular = function(p) p,
member = function(p) p * 0.9,
staff = function(p) p * 0.7
)
for (who in c("regular", "member", "staff")) cat(who, pricing[[who]](50), "\n")出力:
regular 50
member 45
staff 35 設定を持つ戦略はファクトリによって構築されます。percent_off(10)は、割引率を記憶する新しい戦略関数を返します:
percent_off <- function(pct) function(total) total * (1 - pct / 100)
fixed_off <- function(amount) function(total) max(0, total - amount)
rules <- list(percent_off(10), percent_off(25), fixed_off(30))
print(vapply(rules, function(r) r(100), numeric(1)))出力:
[1] 90 75 70オブジェクトはその戦略をフィールドに保持し、後から切り替えることができます。オブジェクトの残りの部分はそのままです。
new_sorter <- function(key) structure(list(key = key), class = "sorter")
sort_with <- function(s, words) words[order(s$key(words))]
by_length <- function(w) nchar(w)
by_last_letter <- function(w) substring(w, nchar(w))
s <- new_sorter(by_length)
words <- c("pear", "fig", "banana")
print(sort_with(s, words))
s$key <- by_last_letter
print(sort_with(s, words))出力:
[1] "fig" "pear" "banana"
[1] "banana" "fig" "pear" チャレンジ
簡単送料は戦略によって選択されます。戦略とは、カートの合計重量と小計を受け取り、送料を返す関数です。Strategies.Rに次の内容を記述してください。
standard(kg, subtotal):4.99に、1kgあたり1を加えた料金。express(kg, subtotal):標準料金の2倍。free_over(limit):小計がlimit以上の場合は料金0、それ以外の場合は標準料金となる戦略を返します。
Cart.Rでは、new_cart(strategy)とadd_item()が与えられています。カートの戦略を呼び出すsubtotal(cart)とshipping_cost(cart)を完成させてください。提供されたコードは戦略(standard、express、またはfree_over 50)を読み込み、次に商品book 12 0.5(名前、価格、kg)を読み込み、合計を出力します。
コードはStrategies.RとCart.Rに記述します。main.Rには提供された入出力コードが含まれており、編集できません。
自分で試してみよう
source("Strategies.R")
source("Cart.R")
# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], " ")[[1]]
rule <- if (p[1] == "free_over") free_over(as.numeric(p[2])) else get(p[1])
cart <- new_cart(rule)
for (line in input[-1]) {
q <- strsplit(line, " ")[[1]]
cart <- add_item(cart, q[1], as.numeric(q[2]), as.numeric(q[3]))
}
cat(sprintf("items: %.2f, shipping: %.2f, total: %.2f", subtotal(cart), shipping_cost(cart), subtotal(cart) + shipping_cost(cart)), "\n", sep = "")
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ