전략 패턴
Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 45번째.
전략 패턴은 알고리즘의 한 부분을 자체 객체로 분리하고 주 객체가 그 객체에 작업을 위임하도록 합니다. 전략을 교체하면 주 클래스를 변경하지 않고도 동작을 바꿀 수 있습니다:
class Standard
def cost(kg)
5 + kg * 1.5
end
end
class Express
def cost(kg)
15 + kg * 3
end
end
class Shipment
attr_writer :strategy
def initialize(kg, strategy)
@kg = kg
@strategy = strategy
end
def cost
@strategy.cost(@kg)
end
end
s = Shipment.new(2, Standard.new)
puts s.cost
s.strategy = Express.new
puts s.cost출력:
8.0
21전략들은 메서드 이름만 공유하므로 cost가 있는 객체라면 무엇이든 작동합니다. 다시 말해 덕 타이핑입니다. 새로운 배송 방식을 추가한다는 것은 Shipment 내부에 또 다른 분기를 추가하는 것이 아니라 클래스 하나를 추가하는 것을 의미합니다:
class Pickup
def cost(_kg)
0
end
end
shipment.strategy = Pickup.new # Shipment는 변경되지 않음Ruby에서 전략은 흔히 람다입니다. call에 응답하는 것이라면 무엇이든 저장하고 호출할 수 있습니다. 람다, 메서드 객체 또는 직접 만든 클래스의 객체인지 여부와 관계없습니다:
class TextFormatter
def initialize(strategy)
@strategy = strategy
end
def format_all(words)
words.map { |w| @strategy.call(w) }.join(" ")
end
end
class Censor
def call(word)
word.size > 3 ? "*" * word.size : word
end
end
words = %w[ruby is great]
puts TextFormatter.new(->(w) { w.upcase }).format_all(words)
puts TextFormatter.new(:capitalize.to_proc).format_all(words)
puts TextFormatter.new(Censor.new).format_all(words)출력:
RUBY IS GREAT
Ruby Is Great
**** is *****프로그램이 실행되는 동안 하나의 객체가 동작을 변경해야 하거나 변형이 단일 단계인 경우에는 서브클래스보다 전략을 선택하세요. 서브클래스는 객체의 전체 수명 동안 동작을 고정합니다:
# 서브클래싱: 생성 시 고정
ExpressShipment.new(2)
# 전략: 나중에 변경 가능
shipment = Shipment.new(2, Standard.new)
shipment.strategy = Express.new챌린지
쉬움배송 전략과 ShippingCalculator를 완성하세요. Standard#cost(kg)는 5에 kg당 1.50을 더한 값이고, Express#cost(kg)는 15에 kg당 3을 더한 값이며, Pickup#cost(kg)는 0입니다. 계산기는 전략과 함께 생성되며 strategy=를 사용해 전략을 변경할 수 있고, quote(kg)는 전략의 클래스 이름을 사용하여 2.5 kg by Express: 22.50을 반환합니다.
제공된 코드는 Standard로 시작하며 use express, use pickup, use standard 또는 quote 2.5 명령을 읽고 모든 견적을 출력합니다.
코드는 standard.rb, express.rb, pickup.rb 및 shipping_calculator.rb에 작성합니다. main.rb에는 제공된 입력/출력 코드가 들어 있으며 수정할 수 없습니다.
직접 해보기
require_relative 'standard'
require_relative 'express'
require_relative 'pickup'
require_relative 'shipping_calculator'
# 제공된 입력/출력 코드: 있는 그대로 유지하세요
input = []
while (line = gets)
input << line.chomp
end
strategies = { "standard" => Standard, "express" => Express, "pickup" => Pickup }
calc = ShippingCalculator.new(Standard.new)
input.each do |line|
cmd, arg = line.split
if cmd == "use"
calc.strategy = strategies[arg].new
else
puts calc.quote(arg.to_f)
end
end
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Ruby 컴파일러